<commit_before>// http://rosettacode.org/wiki/MD5/Implementation

//! Ported from C - Simple MD5 implementation
//! on Wikipedia https://en.wikipedia.org/wiki/MD5

#![feature(step_by)]

use std::num::Wrapping as wr;
use std::fmt::{Debug, Formatter, Result};

fn main() {
    let inputs =
        [&b"a"[..],
         &b"abc"[..],
         &b"message digest"[..],
         &b"abcdefghijklmnopqrstuvwxyz"[..],
         &b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"[..],
         &b"12345678901234567890123456789012345678901234567890123456789012345678901234567890"[..]];

    for &input in &inputs {
        println!("{:?}", md5(input));
    }
}

/// Constants are the integer part of the sines of integers (in radians) * 2^32.
const K: [u32; 64] = [0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,
                      0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
                      0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340,
                      0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
                      0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
                      0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
                      0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
                      0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
                      0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
                      0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
                      0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391];

/// R specifies the per-round shift amounts
const R: [u32; 64] = [7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5,
                      9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11,
                      16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10,
                      15, 21];

/// "newtype" for [u8; 16] to specify it's a MD5 hash
struct MD5([u8; 16]);

impl Debug for MD5 {
    fn fmt(&self, f: &mut Formatter) -> Result {
        let MD5(md5) = *self;
        for b in &md5 {
            try!(write!(f, "{:02x}", *b));
        }
        Ok(())
    }
}

fn to_bytes(val: u64) -> [u8; 8] {
    let mut tmp: [u8; 8] = [0u8; 8];
    for (i, byte) in tmp.iter_mut().enumerate() {
        *byte = (val >> (8 * i)) as u8;
    }
    tmp
}

fn md5(initial_msg: &[u8]) -> MD5 {
    let initial_len = initial_msg.len() as u64;

    // These vars will contain the hash
    let mut h: [wr<u32>; 4] = [wr(0x67452301u32), wr(0xefcdab89), wr(0x98badcfe), wr(0x10325476)];

    // Pre-processing:
    // append "1" bit to message
    // append "0" bits until message length in bits ≡ 448 (mod 512)
    // append length mod (2^64) to message
    let mut new_len = initial_len;
    while new_len % (512 / 8) != 448 / 8 {
        new_len += 1;
    }

    let mut msg = initial_msg.to_vec();
    msg.push(0x80u8); // append the "1" bit; most significant bit is "first"

    for _ in (initial_len + 1)..new_len {
        msg.push(0); // append "0" bits
    }

    // append the len in bits at the end of the buffer.
    msg.extend(&to_bytes(initial_len << 3));

    assert_eq!(msg.len() % 64, 0);

    let mut w: [u32; 16] = [0u32; 16];
    // Process the message in successive 512-bit chunks:
    // for each 512-bit chunk of message:
    for offset in (0u64..new_len).step_by(512 / 8) {
        // break chunk into sixteen 32-bit words w[j], 0 ≤ j ≤ 15
        for i in 0u32..16 {
            let j = i as usize * 4 + offset as usize;
            w[i as usize] = (msg[j] as u32) | (msg[j + 1] as u32) << 8 | (msg[j + 2] as u32) << 16 |
                            (msg[j + 3] as u32) << 24;
        }

        // Initialize hash value for this chunk:
        let (mut a, mut b, mut c, mut d) = (h[0], h[1], h[2], h[3]);

        // Main loop:
        for ind in 0..64 {
            let (f, g) = match ind {
                i @ 0...15 => ((b & c) | ((!b) & d) /* f */, i),                   //g
                i @ 16...31 => ((d & b) | ((!d) & c), (5 * i + 1) % 16),
                i @ 32...47 => (b ^ c ^ d, (3 * i + 5) % 16),
                i => (c ^ (b | (!d)), (7 * i) % 16),
            };

            let temp = d;
            d = c;
            c = b;
            b = b + wr((a + f + wr(K[ind]) + wr(w[g])).0.rotate_left(R[ind]));
            a = temp;
        }

        // Add this chunk's hash to result so far:
        h[0] = h[0] + a;
        h[1] = h[1] + b;
        h[2] = h[2] + c;
        h[3] = h[3] + d;
    }
    drop(msg); // cleanup, msg is freed

    // var char digest[16] := h0 append h1 append h2 append h3 //(Output is in little-endian)
    let mut digest = [0u8; 16];
    for (i, s) in h.iter().enumerate() {
        digest[i * 4] = (*s).0 as u8;
        digest[i * 4 + 1] = (*s >> 8).0 as u8;
        digest[i * 4 + 2] = (*s >> 16).0 as u8;
        digest[i * 4 + 3] = (*s >> 24).0 as u8;
    }
    MD5(digest)
}

#[test]
fn helper_fns() {
    assert_eq!(64, 8u32.rotate_left(3));

    let exp: [u8; 8] = [64u8, 226, 1, 0, 0, 0, 0, 0];
    assert!(to_bytes(123456) == exp);
}

#[test]
fn known_hashes() {
    let in_out =
        [(&b""[..], "d41d8cd98f00b204e9800998ecf8427e"),
         (&b"a"[..], "0cc175b9c0f1b6a831c399e269772661"),
         (&b"abc"[..], "900150983cd24fb0d6963f7d28e17f72"),
         (&b"message digest"[..], "f96b697d7cb7938d525a2f31aaf161d0"),
         (&b"abcdefghijklmnopqrstuvwxyz"[..],
          "c3fcd3d76192e4007dfb496cca67e13b"),
         (&b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"[..],
          "d174ab98d277d9f5a5611c2c9f419d9f"),
         (&b"12345678901234567890123456789012345678901234567890123456789012345678901234567890"[..],
          "57edf4a22be3c955ac49da2e2107b67a")];

    for &(i, o) in &in_out {
        let m = md5(i);
        assert_eq!(format!("{:?}", m), o.to_string());
    }
}
<commit_msg>use `extend_from_slice` when extending by a slice<commit_after>// http://rosettacode.org/wiki/MD5/Implementation

//! Ported from C - Simple MD5 implementation
//! on Wikipedia https://en.wikipedia.org/wiki/MD5

#![feature(step_by)]

use std::num::Wrapping as wr;
use std::fmt::{Debug, Formatter, Result};

fn main() {
    let inputs =
        [&b"a"[..],
         &b"abc"[..],
         &b"message digest"[..],
         &b"abcdefghijklmnopqrstuvwxyz"[..],
         &b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"[..],
         &b"12345678901234567890123456789012345678901234567890123456789012345678901234567890"[..]];

    for &input in &inputs {
        println!("{:?}", md5(input));
    }
}

/// Constants are the integer part of the sines of integers (in radians) * 2^32.
const K: [u32; 64] = [0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,
                      0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
                      0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340,
                      0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
                      0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
                      0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
                      0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
                      0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
                      0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
                      0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
                      0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391];

/// R specifies the per-round shift amounts
const R: [u32; 64] = [7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5,
                      9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11,
                      16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10,
                      15, 21];

/// "newtype" for [u8; 16] to specify it's a MD5 hash
struct MD5([u8; 16]);

impl Debug for MD5 {
    fn fmt(&self, f: &mut Formatter) -> Result {
        let MD5(md5) = *self;
        for b in &md5 {
            try!(write!(f, "{:02x}", *b));
        }
        Ok(())
    }
}

fn to_bytes(val: u64) -> [u8; 8] {
    let mut tmp: [u8; 8] = [0u8; 8];
    for (i, byte) in tmp.iter_mut().enumerate() {
        *byte = (val >> (8 * i)) as u8;
    }
    tmp
}

fn md5(initial_msg: &[u8]) -> MD5 {
    let initial_len = initial_msg.len() as u64;

    // These vars will contain the hash
    let mut h: [wr<u32>; 4] = [wr(0x67452301u32), wr(0xefcdab89), wr(0x98badcfe), wr(0x10325476)];

    // Pre-processing:
    // append "1" bit to message
    // append "0" bits until message length in bits ≡ 448 (mod 512)
    // append length mod (2^64) to message
    let mut new_len = initial_len;
    while new_len % (512 / 8) != 448 / 8 {
        new_len += 1;
    }

    let mut msg = initial_msg.to_vec();
    msg.push(0x80u8); // append the "1" bit; most significant bit is "first"

    for _ in (initial_len + 1)..new_len {
        msg.push(0); // append "0" bits
    }

    // append the len in bits at the end of the buffer.
    msg.extend_from_slice(&to_bytes(initial_len << 3));

    assert_eq!(msg.len() % 64, 0);

    let mut w: [u32; 16] = [0u32; 16];
    // Process the message in successive 512-bit chunks:
    // for each 512-bit chunk of message:
    for offset in (0u64..new_len).step_by(512 / 8) {
        // break chunk into sixteen 32-bit words w[j], 0 ≤ j ≤ 15
        for i in 0u32..16 {
            let j = i as usize * 4 + offset as usize;
            w[i as usize] = (msg[j] as u32) | (msg[j + 1] as u32) << 8 | (msg[j + 2] as u32) << 16 |
                            (msg[j + 3] as u32) << 24;
        }

        // Initialize hash value for this chunk:
        let (mut a, mut b, mut c, mut d) = (h[0], h[1], h[2], h[3]);

        // Main loop:
        for ind in 0..64 {
            let (f, g) = match ind {
                i @ 0...15 => ((b & c) | ((!b) & d) /* f */, i),                   //g
                i @ 16...31 => ((d & b) | ((!d) & c), (5 * i + 1) % 16),
                i @ 32...47 => (b ^ c ^ d, (3 * i + 5) % 16),
                i => (c ^ (b | (!d)), (7 * i) % 16),
            };

            let temp = d;
            d = c;
            c = b;
            b = b + wr((a + f + wr(K[ind]) + wr(w[g])).0.rotate_left(R[ind]));
            a = temp;
        }

        // Add this chunk's hash to result so far:
        h[0] = h[0] + a;
        h[1] = h[1] + b;
        h[2] = h[2] + c;
        h[3] = h[3] + d;
    }
    drop(msg); // cleanup, msg is freed

    // var char digest[16] := h0 append h1 append h2 append h3 //(Output is in little-endian)
    let mut digest = [0u8; 16];
    for (i, s) in h.iter().enumerate() {
        digest[i * 4] = (*s).0 as u8;
        digest[i * 4 + 1] = (*s >> 8).0 as u8;
        digest[i * 4 + 2] = (*s >> 16).0 as u8;
        digest[i * 4 + 3] = (*s >> 24).0 as u8;
    }
    MD5(digest)
}

#[test]
fn helper_fns() {
    assert_eq!(64, 8u32.rotate_left(3));

    let exp: [u8; 8] = [64u8, 226, 1, 0, 0, 0, 0, 0];
    assert!(to_bytes(123456) == exp);
}

#[test]
fn known_hashes() {
    let in_out =
        [(&b""[..], "d41d8cd98f00b204e9800998ecf8427e"),
         (&b"a"[..], "0cc175b9c0f1b6a831c399e269772661"),
         (&b"abc"[..], "900150983cd24fb0d6963f7d28e17f72"),
         (&b"message digest"[..], "f96b697d7cb7938d525a2f31aaf161d0"),
         (&b"abcdefghijklmnopqrstuvwxyz"[..], "c3fcd3d76192e4007dfb496cca67e13b"),
         (&b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"[..],
          "d174ab98d277d9f5a5611c2c9f419d9f"),
         (&b"12345678901234567890123456789012345678901234567890123456789012345678901234567890"[..],
          "57edf4a22be3c955ac49da2e2107b67a")];

    for &(i, o) in &in_out {
        let m = md5(i);
        assert_eq!(format!("{:?}", m), o.to_string());
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(clippy)]

#![deny(clippy)]
#![allow(unused_variables)]
#![allow(unused_assignments)]
#![allow(if_same_then_else)]
#![allow(deref_addrof)]

fn foo() -> bool { true }

fn main() {
    // weird `else if` formatting:
    if foo() {
    } if foo() {
    //~^ ERROR this looks like an `else if` but the `else` is missing
    //~| NOTE add the missing `else` or
    }

    let _ = { // if as the last expression
        let _ = 0;

        if foo() {
        } if foo() {
        //~^ ERROR this looks like an `else if` but the `else` is missing
        //~| NOTE add the missing `else` or
        }
        else {
        }
    };

    let _ = { // if in the middle of a block
        if foo() {
        } if foo() {
        //~^ ERROR this looks like an `else if` but the `else` is missing
        //~| NOTE add the missing `else` or
        }
        else {
        }

        let _ = 0;
    };

    if foo() {
    } else
    //~^ ERROR this is an `else if` but the formatting might hide it
    //~| NOTE remove the `else` or
    if foo() { // the span of the above error should continue here
    }

    if foo() {
    }
    //~^ ERROR this is an `else if` but the formatting might hide it
    //~| NOTE remove the `else` or
    else
    if foo() { // the span of the above error should continue here
    }

    // those are ok:
    if foo() {
    }
    if foo() {
    }

    if foo() {
    } else if foo() {
    }

    if foo() {
    }
    else if foo() {
    }

    if foo() {
    }

    else if

    foo() {}

    // weird op_eq formatting:
    let mut a = 42;
    a =- 35;
    //~^ ERROR this looks like you are trying to use `.. -= ..`, but you really are doing `.. = (- ..)`
    //~| NOTE to remove this lint, use either `-=` or `= -`
    a =* &191;
    //~^ ERROR this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)`
    //~| NOTE to remove this lint, use either `*=` or `= *`

    let mut b = true;
    b =! false;
    //~^ ERROR this looks like you are trying to use `.. != ..`, but you really are doing `.. = (! ..)`
    //~| NOTE to remove this lint, use either `!=` or `= !`

    // those are ok:
    a = -35;
    a = *&191;
    b = !false;

    // possible missing comma in an array
    let mut c = &[
        -1, -2, -3 // <= no coma here
        //~^ ERROR possibly missing a comma here
        //~| NOTE to remove this lint, add a comma or write the expr in a single line
        -4, -5, -6
    ];
}
<commit_msg>Add test cases for possible missing comma lint<commit_after>#![feature(plugin)]
#![plugin(clippy)]

#![deny(clippy)]
#![allow(unused_variables)]
#![allow(unused_assignments)]
#![allow(if_same_then_else)]
#![allow(deref_addrof)]

fn foo() -> bool { true }

fn main() {
    // weird `else if` formatting:
    if foo() {
    } if foo() {
    //~^ ERROR this looks like an `else if` but the `else` is missing
    //~| NOTE add the missing `else` or
    }

    let _ = { // if as the last expression
        let _ = 0;

        if foo() {
        } if foo() {
        //~^ ERROR this looks like an `else if` but the `else` is missing
        //~| NOTE add the missing `else` or
        }
        else {
        }
    };

    let _ = { // if in the middle of a block
        if foo() {
        } if foo() {
        //~^ ERROR this looks like an `else if` but the `else` is missing
        //~| NOTE add the missing `else` or
        }
        else {
        }

        let _ = 0;
    };

    if foo() {
    } else
    //~^ ERROR this is an `else if` but the formatting might hide it
    //~| NOTE remove the `else` or
    if foo() { // the span of the above error should continue here
    }

    if foo() {
    }
    //~^ ERROR this is an `else if` but the formatting might hide it
    //~| NOTE remove the `else` or
    else
    if foo() { // the span of the above error should continue here
    }

    // those are ok:
    if foo() {
    }
    if foo() {
    }

    if foo() {
    } else if foo() {
    }

    if foo() {
    }
    else if foo() {
    }

    if foo() {
    }

    else if

    foo() {}

    // weird op_eq formatting:
    let mut a = 42;
    a =- 35;
    //~^ ERROR this looks like you are trying to use `.. -= ..`, but you really are doing `.. = (- ..)`
    //~| NOTE to remove this lint, use either `-=` or `= -`
    a =* &191;
    //~^ ERROR this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)`
    //~| NOTE to remove this lint, use either `*=` or `= *`

    let mut b = true;
    b =! false;
    //~^ ERROR this looks like you are trying to use `.. != ..`, but you really are doing `.. = (! ..)`
    //~| NOTE to remove this lint, use either `!=` or `= !`

    // those are ok:
    a = -35;
    a = *&191;
    b = !false;

    // possible missing comma in an array
    let _ = &[
        -1, -2, -3 // <= no coma here
        //~^ ERROR possibly missing a comma here
        //~| NOTE to remove this lint, add a comma or write the expr in a single line
        -4, -5, -6
    ];
    let _ = &[
        -1, -2, -3 // <= no coma here
        //~^ ERROR possibly missing a comma here
        //~| NOTE to remove this lint, add a comma or write the expr in a single line
        *4, -5, -6
    ];

    // those are ok:
    let _ = &[
        -1, -2, -3,
        -4, -5, -6
    ];
    let _ = &[
        -1, -2, -3,
        -4, -5, -6,
    ];
    let _ = &[
        1 + 2, 3 +
        4, 5 + 6,
    ];
}
<|endoftext|>


<commit_before>extern crate env_logger;
#[macro_use] extern crate log;
extern crate rl_sys;
extern crate nix;

use std::cell::RefCell;
use std::collections::HashMap;
use std::ffi::CString;
use std::io;
use std::rc::Rc;
use rl_sys::readline;

use nix::libc;

mod directive;
use InputType::*;

extern crate flang_errors as errors;
use errors::{Handler};
use errors::emitter::{ColorConfig, EmitterWriter};
extern crate parser;
use parser::ast::StmtKind::*;
use parser::codemap::CodeMap;
use parser::lexer::{Reader, StringReader};
use parser::parser::{filemap_to_parser, parse_tts_from_source_str, ParseSess, Parser, PResult};
use parser::tokenstream::TokenTree;

static DEFAULT_PROMPT: &'static str = "\x1b[33mflang> \x1b[0m";
static REPL_DUMMY_FILENAME: &'static str = "console.fl";

pub enum InputType<'a> {
  Directive(&'a str, Vec<&'a str>),
  ExternalComamnd(&'a str),
  ExecuteSource(&'a str),
  Empty,
}

pub enum ReplAction {
  Done,
  Continue(String),
  Quit
}

pub struct Repl {
  src_file: SourceFile,
  parsess: ParseSess,
  sout: Rc<RefCell<io::Write>>, // stream out,
  serr: Rc<RefCell<io::Write>>, // stream err,
}

impl Repl {
  pub fn new(sout: Rc<RefCell<io::Write>>, serr: Rc<RefCell<io::Write>>) -> Repl {
    Repl {
      src_file: SourceFile::new(),
      parsess: ParseSess::new(),
      sout: sout,
      serr: serr,
    }
  }

  pub fn write_out(&self, msg: &[u8]) {
    self.sout.borrow_mut().write(msg).ok();
  }

  pub fn flush_out(&self) {
    self.sout.borrow_mut().flush().ok();
  }

  pub fn write_err(&self, msg: &[u8]) {
    self.sout.borrow_mut().write(msg).ok();
  }

  pub fn flush_err(&self) {
    self.sout.borrow_mut().flush().ok();
  }

  pub fn run(&mut self) {
    self.write_out(b"Welcome to Flang version 0.1. (Type :help for assistance.)\n");
    self.flush_out();

    let mut state = ReplState::new();

    let mut prompt: String = DEFAULT_PROMPT.to_string();

    loop {
      match readline::readline(&prompt) {
        Ok(Some(line)) => {
          match self.handle_line(&line) {
            ReplAction::Done => { prompt = DEFAULT_PROMPT.to_string(); }
            ReplAction::Continue(p) => prompt = p,
            ReplAction::Quit => break
          }
        }
        Ok(None) => break, // eof
        Err(msg) => {
          self.write_err(format!("ERROR: {}", msg).as_bytes());
        }
      }
    }
  }

  fn handle_line(&mut self, line: &str) -> ReplAction {
    match self.parse_input(line) {
      Directive(d, args) => self.exec_directive(d, args),
      ExecuteSource(line) => self.exec_line(line),
      ExternalComamnd(command) => self.exec_external_program(command),
      Empty => ReplAction::Done // just enter without any type
    }
  }

  fn parse_input<'a>(&self, line: &'a str) -> InputType<'a> {
    let mut tokens = line.split_whitespace();
    let first_token = tokens.next();

    match first_token {
      Some(first) => match first {
        x if x.starts_with(':') => Directive(&first[1..], tokens.collect::<Vec<_>>()),
        x if x.starts_with('!') => ExternalComamnd(&line[1..]),
        _ => ExecuteSource(line)
      },
      None => Empty
    }
  }

  pub fn exec_directive(&self, directive: &str, args: Vec<&str>) -> ReplAction {
    match directive {
      "dump" => {
        self.write_out(self.src_file.as_bytes());
        ReplAction::Done
      }
      "quit" => ReplAction::Quit,
      _ => ReplAction::Done
    }
  }

  pub fn exec_line(&mut self, line: &str) -> ReplAction {
    let cm = Rc::new(CodeMap::new());
    let emitter = Box::new(EmitterWriter::stderr(ColorConfig::Auto, Some(cm.clone())));
    let handler = Handler::with_emitter(true, false, emitter);
    let parsess = ParseSess::with_span_handler(handler, cm.clone());

    let mut parser = parse_flang(&parsess, line);
    self.src_file.add_line(line);

    match parser.parse_item() {
      Ok(Some(item)) => {
        println!("item");
        return ReplAction::Done
      }
      Ok(None) => println!("no item"),
      Err(ref mut e) => {
        println!("not item");
        e.cancel();
      }
    };

    match parser.parse_full_stmt() {
      Ok(Some(stmt)) => {
        match stmt.node {
          Local(l) => println!("local"),
          Item(i) => println!("item"),
          Expr(e) => println!("expr"),
          Semi(s) => println!("semi"),
        }
      }
      Ok(None) => println!("no stmt"),
      Err(e) => println!("not stmt"),
    };

    ReplAction::Done

    // append source
    // generate mir
    // check ast error
    // add source which is valid
    // skip if the source doesn't need to run
    // generate llvm ir and module
    // reorganize llvm module
  }

  pub fn exec_external_program(&self, command: &str) -> ReplAction {
    let c_to_print = CString::new(command).unwrap();
    unsafe { libc::system(c_to_print.as_ptr()); }
    ReplAction::Done
  }
}

fn parse_flang<'a>(parsess: &'a ParseSess, line: &str) -> Parser<'a> {
  let filemap = parsess.codemap().new_filemap_and_lines("console.fl", None, line);
  filemap_to_parser(&parsess, filemap)
}

fn parse_flang2<'a>(parsess: &'a ParseSess, line: &str) -> PResult<'a, Vec<TokenTree>> {
  let filemap = parsess.codemap().new_filemap_and_lines("console.fl", None, line);
  let sdr = StringReader::new(&parsess.span_diagnostic, filemap);
  let mut p = Parser::new(parsess, Box::new(sdr));
  p.parse_all_token_trees()
}

pub struct ReplState;

impl ReplState {
  pub fn new() -> ReplState {
    ReplState
  }
}

pub struct SourceFile {
  source: String
}

impl SourceFile {
  pub fn new() -> SourceFile {
    SourceFile { source : String::new() }
  }

  pub fn add_line(&mut self, line: &str) {
    self.source.push_str(line);
    self.source.push_str("\n");
  }

  pub fn as_str(&self) -> &str {
    &self.source
  }

  pub fn as_bytes(&self) -> &[u8] {
    self.source.as_bytes()
  }
}

<commit_msg>Add ReplEmitter<commit_after>extern crate env_logger;
#[macro_use] extern crate log;
extern crate rl_sys;
extern crate nix;

use std::cell::RefCell;
use std::collections::HashMap;
use std::ffi::CString;
use std::io;
use std::rc::Rc;
use rl_sys::readline;

use nix::libc;

mod directive;
use InputType::*;

extern crate flang_errors as errors;
use errors::{DiagnosticBuilder, Handler};
use errors::emitter::{ColorConfig, Emitter, EmitterWriter};
extern crate parser;
use parser::ast::StmtKind::*;
use parser::codemap::CodeMap;
use parser::lexer::{Reader, StringReader};
use parser::parser::{filemap_to_parser, parse_tts_from_source_str, ParseSess, Parser, PResult};
use parser::tokenstream::TokenTree;

static DEFAULT_PROMPT: &'static str = "\x1b[33mflang> \x1b[0m";
static REPL_DUMMY_FILENAME: &'static str = "console.fl";

pub enum InputType<'a> {
  Directive(&'a str, Vec<&'a str>),
  ExternalComamnd(&'a str),
  ExecuteSource(&'a str),
  Empty,
}

pub enum ReplAction {
  Done,
  Continue(String),
  Quit
}

pub struct Repl {
  src_file: SourceFile,
  parsess: ParseSess,
  sout: Rc<RefCell<io::Write>>, // stream out,
  serr: Rc<RefCell<io::Write>>, // stream err,
}

impl Repl {
  pub fn new(sout: Rc<RefCell<io::Write>>, serr: Rc<RefCell<io::Write>>) -> Repl {
    Repl {
      src_file: SourceFile::new(),
      parsess: ParseSess::new(),
      sout: sout,
      serr: serr,
    }
  }

  pub fn write_out(&self, msg: &[u8]) {
    self.sout.borrow_mut().write(msg).ok();
  }

  pub fn flush_out(&self) {
    self.sout.borrow_mut().flush().ok();
  }

  pub fn write_err(&self, msg: &[u8]) {
    self.sout.borrow_mut().write(msg).ok();
  }

  pub fn flush_err(&self) {
    self.sout.borrow_mut().flush().ok();
  }

  pub fn run(&mut self) {
    self.write_out(b"Welcome to Flang version 0.1. (Type :help for assistance.)\n");
    self.flush_out();

    let mut state = ReplState::new();

    let mut prompt: String = DEFAULT_PROMPT.to_string();

    loop {
      match readline::readline(&prompt) {
        Ok(Some(line)) => {
          match self.handle_line(&line) {
            ReplAction::Done => { prompt = DEFAULT_PROMPT.to_string(); }
            ReplAction::Continue(p) => prompt = p,
            ReplAction::Quit => break
          }
        }
        Ok(None) => break, // eof
        Err(msg) => {
          self.write_err(format!("ERROR: {}", msg).as_bytes());
        }
      }
    }
  }

  fn handle_line(&mut self, line: &str) -> ReplAction {
    match self.parse_input(line) {
      Directive(d, args) => self.exec_directive(d, args),
      ExecuteSource(line) => self.exec_line(line),
      ExternalComamnd(command) => self.exec_external_program(command),
      Empty => ReplAction::Done // just enter without any type
    }
  }

  fn parse_input<'a>(&self, line: &'a str) -> InputType<'a> {
    let mut tokens = line.split_whitespace();
    let first_token = tokens.next();

    match first_token {
      Some(first) => match first {
        x if x.starts_with(':') => Directive(&first[1..], tokens.collect::<Vec<_>>()),
        x if x.starts_with('!') => ExternalComamnd(&line[1..]),
        _ => ExecuteSource(line)
      },
      None => Empty
    }
  }

  pub fn exec_directive(&self, directive: &str, args: Vec<&str>) -> ReplAction {
    match directive {
      "dump" => {
        self.write_out(self.src_file.as_bytes());
        ReplAction::Done
      }
      "quit" => ReplAction::Quit,
      _ => ReplAction::Done
    }
  }

  pub fn exec_line(&mut self, line: &str) -> ReplAction {
    let cm = Rc::new(CodeMap::new());
    let emitter = Box::new(ReplEmitter::new(cm.clone()));
    let handler = Handler::with_emitter(true, false, emitter);
    let parsess = ParseSess::with_span_handler(handler, cm.clone());

    let mut parser = parse_flang(&parsess, line);
    self.src_file.add_line(line);

    match parser.parse_item() {
      Ok(Some(item)) => {
        println!("item");
        return ReplAction::Done
      }
      Ok(None) => println!("no item"),
      Err(ref mut e) => {
        println!("not item");
        e.cancel();
      }
    };

    match parser.parse_full_stmt() {
      Ok(Some(stmt)) => {
        match stmt.node {
          Local(l) => println!("local"),
          Item(i) => println!("item"),
          Expr(e) => println!("expr"),
          Semi(s) => println!("semi"),
        }
      }
      Ok(None) => println!("no stmt"),
      Err(e) => println!("not stmt"),
    };

    ReplAction::Done

    // append source
    // generate mir
    // check ast error
    // add source which is valid
    // skip if the source doesn't need to run
    // generate llvm ir and module
    // reorganize llvm module
  }

  pub fn exec_external_program(&self, command: &str) -> ReplAction {
    let c_to_print = CString::new(command).unwrap();
    unsafe { libc::system(c_to_print.as_ptr()); }
    ReplAction::Done
  }
}

fn parse_flang<'a>(parsess: &'a ParseSess, line: &str) -> Parser<'a> {
  let filemap = parsess.codemap().new_filemap_and_lines("console.fl", None, line);
  filemap_to_parser(&parsess, filemap)
}

fn parse_flang2<'a>(parsess: &'a ParseSess, line: &str) -> PResult<'a, Vec<TokenTree>> {
  let filemap = parsess.codemap().new_filemap_and_lines("console.fl", None, line);
  let sdr = StringReader::new(&parsess.span_diagnostic, filemap);
  let mut p = Parser::new(parsess, Box::new(sdr));
  p.parse_all_token_trees()
}

pub struct ReplEmitter {
  em: EmitterWriter
}

impl ReplEmitter {
  pub fn new(cm: Rc<CodeMap>) -> ReplEmitter {
    ReplEmitter {
      em: EmitterWriter::stderr(ColorConfig::Auto, Some(cm))
    }
  }
}

impl Emitter for ReplEmitter {
  /// Emit a structured diagnostic.
  fn emit(&mut self, db: &DiagnosticBuilder) {
    self.em.emit(db);
  }
}

pub struct ReplState;

impl ReplState {
  pub fn new() -> ReplState {
    ReplState
  }
}

pub struct SourceFile {
  source: String
}

impl SourceFile {
  pub fn new() -> SourceFile {
    SourceFile { source : String::new() }
  }

  pub fn add_line(&mut self, line: &str) {
    self.source.push_str(line);
    self.source.push_str("\n");
  }

  pub fn as_str(&self) -> &str {
    &self.source
  }

  pub fn as_bytes(&self) -> &[u8] {
    self.source.as_bytes()
  }
}

<|endoftext|>


<commit_before>#![crate_id(name="env", vers="1.0.0", author="LeoTestard")]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: env (GNU coreutils) 8.13 */

#![allow(non_camel_case_types)]

struct options {
    ignore_env: bool,
    null: bool,
    unsets: Vec<~str>,
    sets: Vec<(~str, ~str)>,
    program: Vec<~str>
}

fn usage(prog: &str) {
    println!("Usage: {:s} [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]", prog);
    println!("Set each NAME to VALUE in the environment and run COMMAND\n");
    println!("Possible options are:");
    println!("  -i --ignore-environment\t start with an empty environment");
    println!("  -0 --null              \t end each output line with a 0 byte rather than newline");
    println!("  -u --unset NAME        \t remove variable from the environment");
    println!("  -h --help              \t display this help and exit");
    println!("  -V --version           \t output version information and exit\n");
    println!("A mere - implies -i. If no COMMAND, print the resulting environment");
}

fn version() {
    println!("env 1.0.0");
}

// print name=value env pairs on screen
// if null is true, separate pairs with a \0, \n otherwise
fn print_env(null: bool) {
    let env = std::os::env();

    for &(ref n, ref v) in env.iter() {
        print!("{:s}={:s}{:c}",
            n.as_slice(),
            v.as_slice(),
            if null { '\0' } else { '\n' }
        );
    }
}

fn main() {
    let args = std::os::args();
    let prog = args[0].as_slice();

    // to handle arguments the same way than GNU env, we can't use getopts
    let mut opts = box options {
        ignore_env: false,
        null: false,
        unsets: vec!(),
        sets: vec!(),
        program: vec!()
    };

    let mut wait_cmd = false;
    let mut iter = args.iter();
    iter.next(); // skip program
    let mut item = iter.next();

    // the for loop doesn't work here,
    // because we need sometines to read 2 items forward,
    // and the iter can't be borrowed twice
    while item != None {
        let opt = item.unwrap();

        if wait_cmd {
            // we still accept NAME=VAL here but not other options
            let mut sp = opt.splitn('=', 1);
            let name = sp.next();
            let value = sp.next();

            match (name, value) {
                (Some(n), Some(v)) => {
                    opts.sets.push((n.into_owned(), v.into_owned()));
                }
                _ => {
                    // read the program now
                    opts.program.push(opt.to_owned());
                    break;
                }
            }
        } else if opt.starts_with("--") {
            match opt.as_slice() {
                "--help" => { usage(prog); return }
                "--version" => { version(); return }

                "--ignore-environment" => opts.ignore_env = true,
                "--null" => opts.null = true,
                "--unset" => {
                    let var = iter.next();

                    match var {
                        None => println!("{:s}: this option requires an argument: {:s}", prog, opt.as_slice()),
                        Some(s) => opts.unsets.push(s.to_owned())
                    }
                }

                _ => {
                    println!("{:s}: invalid option \"{:s}\"", prog, *opt);
                    println!("Type \"{:s} --help\" for detailed informations", prog);
                    return
                }
            }
        } else if opt.starts_with("-") {
            if opt.len() == 0 {
                // implies -i and stop parsing opts
                wait_cmd = true;
                opts.ignore_env = true;
                continue;
            }

            let mut chars = opt.chars();
            chars.next();

            for c in chars {
                // short versions of options
                match c {
                    'h' => { usage(prog); return }
                    'V' => { version(); return }
                    'i' => opts.ignore_env = true,
                    '0' => opts.null = true,
                    'u' => {
                        let var = iter.next();

                        match var {
                            None => println!("{:s}: this option requires an argument: {:s}", prog, opt.as_slice()),
                            Some(s) => opts.unsets.push(s.to_owned())
                        }
                    }
                    _ => {
                        println!("{:s}: illegal option -- {:c}", prog, c);
                        println!("Type \"{:s} --help\" for detailed informations", prog);
                        return
                    }
                }
            }
        } else {
            // is it a NAME=VALUE like opt ?
            let mut sp = opt.splitn('=', 1);
            let name = sp.next();
            let value = sp.next();

            match (name, value) {
                (Some(n), Some(v)) => {
                    // yes
                    opts.sets.push((n.into_owned(), v.into_owned()));
                    wait_cmd = true;
                }
                // no, its a program-like opt
                _ => {
                    opts.program.push(opt.to_owned());
                    break;
                }
            }
        }

        item = iter.next();
    }

    // read program arguments
    for opt in iter {
        opts.program.push(opt.to_owned());
    }

    let env = std::os::env();

    if opts.ignore_env {
        for &(ref name, _) in env.iter() {
            std::os::unsetenv(name.as_slice())
        }
    }

    for ref name in opts.unsets.iter() {
        std::os::unsetenv(name.as_slice())
    }

    for &(ref name, ref val) in opts.sets.iter() {
        std::os::setenv(name.as_slice(), val.as_slice())
    }

    if opts.program.len() >= 1 {
        match std::io::process::Process::status(opts.program.get(0).as_slice(), opts.program.slice_from(1)) {
            Ok(exit) =>
                std::os::set_exit_status(match exit {
                    std::io::process::ExitStatus(s) => s,
                    _ => 1
                }),
            Err(_) => std::os::set_exit_status(1)
        }
    } else {
        // no program provided
        print_env(opts.null);
    }
}
<commit_msg>env: os.arg() returns Vec<~str> now<commit_after>#![crate_id(name="env", vers="1.0.0", author="LeoTestard")]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: env (GNU coreutils) 8.13 */

#![allow(non_camel_case_types)]

struct options {
    ignore_env: bool,
    null: bool,
    unsets: Vec<~str>,
    sets: Vec<(~str, ~str)>,
    program: Vec<~str>
}

fn usage(prog: &str) {
    println!("Usage: {:s} [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]", prog);
    println!("Set each NAME to VALUE in the environment and run COMMAND\n");
    println!("Possible options are:");
    println!("  -i --ignore-environment\t start with an empty environment");
    println!("  -0 --null              \t end each output line with a 0 byte rather than newline");
    println!("  -u --unset NAME        \t remove variable from the environment");
    println!("  -h --help              \t display this help and exit");
    println!("  -V --version           \t output version information and exit\n");
    println!("A mere - implies -i. If no COMMAND, print the resulting environment");
}

fn version() {
    println!("env 1.0.0");
}

// print name=value env pairs on screen
// if null is true, separate pairs with a \0, \n otherwise
fn print_env(null: bool) {
    let env = std::os::env();

    for &(ref n, ref v) in env.iter() {
        print!("{:s}={:s}{:c}",
            n.as_slice(),
            v.as_slice(),
            if null { '\0' } else { '\n' }
        );
    }
}

fn main() {
    let args = std::os::args();
    let prog = args.get(0).as_slice();

    // to handle arguments the same way than GNU env, we can't use getopts
    let mut opts = box options {
        ignore_env: false,
        null: false,
        unsets: vec!(),
        sets: vec!(),
        program: vec!()
    };

    let mut wait_cmd = false;
    let mut iter = args.iter();
    iter.next(); // skip program
    let mut item = iter.next();

    // the for loop doesn't work here,
    // because we need sometines to read 2 items forward,
    // and the iter can't be borrowed twice
    while item != None {
        let opt = item.unwrap();

        if wait_cmd {
            // we still accept NAME=VAL here but not other options
            let mut sp = opt.splitn('=', 1);
            let name = sp.next();
            let value = sp.next();

            match (name, value) {
                (Some(n), Some(v)) => {
                    opts.sets.push((n.into_owned(), v.into_owned()));
                }
                _ => {
                    // read the program now
                    opts.program.push(opt.to_owned());
                    break;
                }
            }
        } else if opt.starts_with("--") {
            match opt.as_slice() {
                "--help" => { usage(prog); return }
                "--version" => { version(); return }

                "--ignore-environment" => opts.ignore_env = true,
                "--null" => opts.null = true,
                "--unset" => {
                    let var = iter.next();

                    match var {
                        None => println!("{:s}: this option requires an argument: {:s}", prog, opt.as_slice()),
                        Some(s) => opts.unsets.push(s.to_owned())
                    }
                }

                _ => {
                    println!("{:s}: invalid option \"{:s}\"", prog, *opt);
                    println!("Type \"{:s} --help\" for detailed informations", prog);
                    return
                }
            }
        } else if opt.starts_with("-") {
            if opt.len() == 0 {
                // implies -i and stop parsing opts
                wait_cmd = true;
                opts.ignore_env = true;
                continue;
            }

            let mut chars = opt.chars();
            chars.next();

            for c in chars {
                // short versions of options
                match c {
                    'h' => { usage(prog); return }
                    'V' => { version(); return }
                    'i' => opts.ignore_env = true,
                    '0' => opts.null = true,
                    'u' => {
                        let var = iter.next();

                        match var {
                            None => println!("{:s}: this option requires an argument: {:s}", prog, opt.as_slice()),
                            Some(s) => opts.unsets.push(s.to_owned())
                        }
                    }
                    _ => {
                        println!("{:s}: illegal option -- {:c}", prog, c);
                        println!("Type \"{:s} --help\" for detailed informations", prog);
                        return
                    }
                }
            }
        } else {
            // is it a NAME=VALUE like opt ?
            let mut sp = opt.splitn('=', 1);
            let name = sp.next();
            let value = sp.next();

            match (name, value) {
                (Some(n), Some(v)) => {
                    // yes
                    opts.sets.push((n.into_owned(), v.into_owned()));
                    wait_cmd = true;
                }
                // no, its a program-like opt
                _ => {
                    opts.program.push(opt.to_owned());
                    break;
                }
            }
        }

        item = iter.next();
    }

    // read program arguments
    for opt in iter {
        opts.program.push(opt.to_owned());
    }

    let env = std::os::env();

    if opts.ignore_env {
        for &(ref name, _) in env.iter() {
            std::os::unsetenv(name.as_slice())
        }
    }

    for ref name in opts.unsets.iter() {
        std::os::unsetenv(name.as_slice())
    }

    for &(ref name, ref val) in opts.sets.iter() {
        std::os::setenv(name.as_slice(), val.as_slice())
    }

    if opts.program.len() >= 1 {
        match std::io::process::Process::status(opts.program.get(0).as_slice(), opts.program.slice_from(1)) {
            Ok(exit) =>
                std::os::set_exit_status(match exit {
                    std::io::process::ExitStatus(s) => s,
                    _ => 1
                }),
            Err(_) => std::os::set_exit_status(1)
        }
    } else {
        // no program provided
        print_env(opts.null);
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::ops;
use std::ptr;
use std::slice;
use std::iter;

use nodrop::NoDrop;

use num_traits::{Unsigned, Zero, One};

#[derive(Debug)]
pub struct OverflowError<T1, T2>(pub T1, pub T2);

#[derive(Debug)]
pub enum InsertError<T1, T2> {
    Overflow(T1, T2),
    OutOfBounds(T1, T2)
}

pub unsafe trait Array {
    type Item;
    type Index: Index;
    fn as_ptr(&self) -> *const Self::Item;
    fn as_mut_ptr(&mut self) -> *mut Self::Item;
    fn capacity() -> usize;
}

pub trait Index : Unsigned + ops::AddAssign + ops::SubAssign + Copy {
    fn as_usize(self) -> usize;
    fn from_usize(value: usize) -> Self;
}

macro_rules! impl_index {
    ($index_type:ty) => (
        impl Index for $index_type {
            fn as_usize(self) -> usize {
                self as usize
            }

            fn from_usize(value: usize) -> Self {
                value as $index_type
            }
        }
    )
}

impl_index!(u8);
impl_index!(u16);
impl_index!(u32);
impl_index!(usize);

macro_rules! impl_array {
    ($index_type:ty => $($len:expr),+ $(,)*) => (
        $(
            unsafe impl<T> Array for [T; $len] {
                type Item = T;
                type Index = $index_type;
                #[inline(always)]
                fn as_ptr(&self) -> *const T {
                    self as *const _ as *const _
                }

                #[inline(always)]
                fn as_mut_ptr(&mut self) -> *mut T {
                    self as *mut _ as *mut _
                }

                #[inline(always)]
                fn capacity() -> usize {
                    $len
                }
            }
        )*
    )
}

impl_array!(u8 => 1, 2, 7, 31, 256);

pub struct LockstepArray<A1: Array, A2: Array> {
    len: A1::Index,
    array1: NoDrop<A1>,
    array2: NoDrop<A2>
}

impl<A1, A2> LockstepArray<A1, A2> where A1: Array, A2: Array {
    pub fn new() -> LockstepArray<A1, A2> {
        // TODO: Eventually these will be encoded into the type system
        assert_eq!(A1::capacity(), A2::capacity());
        LockstepArray {
            len: Zero::zero(),
            array1: NoDrop::new(unsafe {mem::uninitialized()}),
            array2: NoDrop::new(unsafe {mem::uninitialized()})
        }
    }

    pub fn from_arrays<B1, B2>(array1: B1, array2: B2) -> LockstepArray<A1, A2>
        where B1: Array<Item=A1::Item>, B2: Array<Item=A2::Item> {
        let mut lockstep = LockstepArray::<A1, A2>::new();
        // TODO: Eventually these will be encoded into the type system
        assert!(B1::capacity() <= A1::capacity());
        assert!(B2::capacity() <= A2::capacity());
        assert_eq!(A1::capacity(), A2::capacity());
        let len = A1::Index::from_usize(A1::capacity());
        unsafe {
            ptr::copy_nonoverlapping(array1.as_ptr(),
                                     lockstep.array1.as_mut_ptr(),
                                     A1::capacity());
            mem::forget(array1);
            ptr::copy_nonoverlapping(array2.as_ptr(),
                                     lockstep.array2.as_mut_ptr(),
                                     A1::capacity());
            mem::forget(array2);
        }
        lockstep.len = len;
        lockstep
    }

    pub fn push(&mut self, item1: A1::Item, item2: A2::Item)
                -> Result<(), OverflowError<A1::Item, A2::Item>> {
        if self.len.as_usize() == A1::capacity() {
            return Err(OverflowError(item1, item2));
        }
        unsafe {
            let p1 = self.array1.as_mut_ptr();
            ptr::write(p1.offset(self.len.as_usize() as isize), item1);
            let p2 = self.array2.as_mut_ptr();
            ptr::write(p2.offset(self.len.as_usize() as isize), item2);
        }
        self.len += One::one();
        Ok(())
    }

    pub fn pop(&mut self) -> Option<(A1::Item, A2::Item)> {
        if self.len == Zero::zero() {
            None
        } else {
            unsafe {
                // Calculate item 1's pointer
                let src1 = self.array1.as_mut_ptr()
                    .offset(self.len.as_usize() as isize);
                // Move item 1 out of the pointer
                let item1 = ptr::read(src1);
                // Calculate item 2's pointer
                let src2 = self.array2.as_mut_ptr()
                    .offset(self.len.as_usize() as isize);
                // Move item 2 out of the pointer
                let item2 = ptr::read(src2);
                // Update length
                self.len -= One::one();
                Some((item1, item2))
            }
        }
    }

    pub fn insert(&mut self, index: usize, item1: A1::Item, item2: A2::Item)
                  -> Result<(), InsertError<A1::Item, A2::Item>> {
        if index > self.len.as_usize() {
            Err(InsertError::OutOfBounds(item1, item2))
        } else if self.len.as_usize() == A1::capacity() {
            Err(InsertError::Overflow(item1, item2))
        } else {
            unsafe {
                // TODO: Tricky math, check indices and such
                let dest1 = self.array1.as_mut_ptr().offset(index as isize);
                ptr::copy(dest1, dest1.offset(1), self.len.as_usize() - index);
                ptr::write(dest1, item1);
                let dest2 = self.array2.as_mut_ptr().offset(index as isize);
                ptr::copy(dest2, dest2.offset(1), self.len.as_usize() - index);
                ptr::write(dest2, item2);
            }
            self.len += One::one();
            Ok(())
        }
    }

    pub fn remove(&mut self, index: usize) -> Option<(A1::Item, A2::Item)> {
        if index >= self.len.as_usize() {
            None
        } else {
            let item1;
            let item2;
            unsafe {
                // Calculate item 1's pointer
                let src1 = self.array1.as_mut_ptr().offset(index as isize);
                // Move item 1 out of the pointer
                item1 = ptr::read(src1);
                // Shift down array 1 down by 1
                ptr::copy(src1.offset(1), src1, self.len.as_usize() - index - 1);
                // Calculate item 2's pointer
                let src2 = self.array2.as_mut_ptr().offset(index as isize);
                // Move item 2 out of the pointer
                item2 = ptr::read(src2);
                // Shift down array 2 down by 1
                ptr::copy(src2.offset(1), src2, self.len.as_usize() - index - 1);
                // Update length
                self.len -= One::one();
            }
            Some((item1, item2))
        }
    }

    pub fn is_empty(&self) -> bool {
        self.len == Zero::zero()
    }

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

    pub fn get(&self, index: usize) -> Option<(&A1::Item, &A2::Item)> {
        if index >= self.len.as_usize() {
            None
        } else {
            let item1 = unsafe {
                &*self.array1.as_ptr().offset(index as isize)
            };
            let item2 = unsafe {
                &*self.array2.as_ptr().offset(index as isize)
            };
            Some((item1, item2))
        }
    }

    pub fn array1(&self) -> &[A1::Item] {
        unsafe {
            let ptr = self.array1.as_ptr();
            let len = self.len.as_usize();
            slice::from_raw_parts(ptr, len)
        }
    }

    pub fn array2(&self) -> &[A2::Item] {
        unsafe {
            let ptr = self.array2.as_ptr();
            let len = self.len.as_usize();
            slice::from_raw_parts(ptr, len)
        }
    }

    pub fn array1_mut(&mut self) -> &mut [A1::Item] {
        unsafe {
            let ptr = self.array1.as_mut_ptr();
            let len = self.len.as_usize();
            slice::from_raw_parts_mut(ptr, len)
        }
    }

    pub fn array2_mut(&mut self) -> &mut [A2::Item] {
        unsafe {
            let ptr = self.array2.as_mut_ptr();
            let len = self.len.as_usize();
            slice::from_raw_parts_mut(ptr, len)
        }
    }

    pub fn capacity(&self) -> usize {
        A1::capacity()
    }
}

impl<A1, A2> Default for LockstepArray<A1, A2> where A1: Array, A2: Array {
    fn default() -> Self {
        Self::new()
    }
}

impl<A1, A2> IntoIterator for LockstepArray<A1, A2> where A1: Array, A2: Array {
    type Item = (A1::Item, A2::Item);
    type IntoIter = IntoIter<A1, A2>;
    fn into_iter(self) -> Self::IntoIter {
        let LockstepArray { len, array1, array2 } = self;
        IntoIter {
            len: len.as_usize(),
            array1: array1,
            array2: array2,
            pos: 0
        }
    }
}

pub struct IntoIter<A1: Array, A2: Array> {
    len: usize,
    array1: NoDrop<A1>,
    array2: NoDrop<A2>,
    pos: usize
}

impl<A1: Array, A2: Array> Iterator for IntoIter<A1, A2> {
    type Item = (A1::Item, A2::Item);
    fn next(&mut self) -> Option<Self::Item> {
        if self.pos == self.len {
            None
        } else {
            unsafe {
                let ptr1 = self.array1.as_mut_ptr().offset(self.pos as isize);
                let item1 = ptr::read(ptr1);
                let ptr2 = self.array2.as_mut_ptr().offset(self.pos as isize);
                let item2 = ptr::read(ptr2);
                self.pos += 1;
                Some((item1, item2))
            }
        }
    }
}

#[test]
fn test_into_iter() {
    let mut locksteparray = LockstepArray::<[u8; 7], [u8; 7]>::new();
    locksteparray.insert(0, 4, 5).unwrap();
    locksteparray.insert(1, 3, 4).unwrap();
    let mut iter = locksteparray.into_iter();
    assert_eq!(iter.next(), Some((4, 5)));
    assert_eq!(iter.next(), Some((3, 4)));
    assert_eq!(iter.next(), None);
}

#[test]
fn test_remove() {
    let mut locksteparray = LockstepArray::<[u8; 7], [u8; 7]>::new();
    locksteparray.push(1, 2).unwrap();
    locksteparray.push(3, 4).unwrap();
    locksteparray.remove(0);
    assert_eq!(locksteparray.get(0), Some((&3, &4)));
    locksteparray.push(5, 6).unwrap();
    locksteparray.remove(1);
    assert_eq!(locksteparray.get(0), Some((&3, &4)));
}

#[test]
fn test_length() {
    let mut locksteparray = LockstepArray::<[u8; 7], [u8; 7]>::new();
    assert_eq!(locksteparray.len(), 0);
    assert!(locksteparray.is_empty());
    locksteparray.insert(0, 4, 5).unwrap();
    assert_eq!(locksteparray.len(), 1);
    locksteparray.insert(1, 3, 4).unwrap();
    assert_eq!(locksteparray.len(), 2);
    locksteparray.pop();
    assert_eq!(locksteparray.len(), 1);
    locksteparray.pop();
    assert_eq!(locksteparray.len(), 0);
    assert!(locksteparray.is_empty());
}

// TODO: Remove when this is detected at compile time.
#[test]
#[should_panic]
fn test_different_sized_arrays() {
    let _ = LockstepArray::<[u8; 2], [u8; 7]>::new();
}
<commit_msg>Fix a panic on inserting third item<commit_after>use std::mem;
use std::ops;
use std::ptr;
use std::slice;
use std::iter;

use nodrop::NoDrop;

use num_traits::{Unsigned, Zero, One};

#[derive(Debug)]
pub struct OverflowError<T1, T2>(pub T1, pub T2);

#[derive(Debug)]
pub enum InsertError<T1, T2> {
    Overflow(T1, T2),
    OutOfBounds(T1, T2)
}

pub unsafe trait Array {
    type Item;
    type Index: Index;
    fn as_ptr(&self) -> *const Self::Item;
    fn as_mut_ptr(&mut self) -> *mut Self::Item;
    fn capacity() -> usize;
}

pub trait Index : Unsigned + ops::AddAssign + ops::SubAssign + Copy {
    fn as_usize(self) -> usize;
    fn from_usize(value: usize) -> Self;
}

macro_rules! impl_index {
    ($index_type:ty) => (
        impl Index for $index_type {
            fn as_usize(self) -> usize {
                self as usize
            }

            fn from_usize(value: usize) -> Self {
                value as $index_type
            }
        }
    )
}

impl_index!(u8);
impl_index!(u16);
impl_index!(u32);
impl_index!(usize);

macro_rules! impl_array {
    ($index_type:ty => $($len:expr),+ $(,)*) => (
        $(
            unsafe impl<T> Array for [T; $len] {
                type Item = T;
                type Index = $index_type;
                #[inline(always)]
                fn as_ptr(&self) -> *const T {
                    self as *const _ as *const _
                }

                #[inline(always)]
                fn as_mut_ptr(&mut self) -> *mut T {
                    self as *mut _ as *mut _
                }

                #[inline(always)]
                fn capacity() -> usize {
                    $len
                }
            }
        )*
    )
}

impl_array!(u8 => 1, 2, 7, 31, 256);

pub struct LockstepArray<A1: Array, A2: Array> {
    len: A1::Index,
    array1: NoDrop<A1>,
    array2: NoDrop<A2>
}

impl<A1, A2> LockstepArray<A1, A2> where A1: Array, A2: Array {
    pub fn new() -> LockstepArray<A1, A2> {
        // TODO: Eventually these will be encoded into the type system
        assert_eq!(A1::capacity(), A2::capacity());
        LockstepArray {
            len: Zero::zero(),
            array1: NoDrop::new(unsafe {mem::uninitialized()}),
            array2: NoDrop::new(unsafe {mem::uninitialized()})
        }
    }

    pub fn from_arrays<B1, B2>(array1: B1, array2: B2) -> LockstepArray<A1, A2>
        where B1: Array<Item=A1::Item>, B2: Array<Item=A2::Item> {
        let mut lockstep = LockstepArray::<A1, A2>::new();
        // TODO: Eventually these will be encoded into the type system
        assert!(B1::capacity() <= A1::capacity());
        assert!(B2::capacity() <= A2::capacity());
        assert_eq!(B1::capacity(), B2::capacity());
        let len = A1::Index::from_usize(B1::capacity());
        unsafe {
            ptr::copy_nonoverlapping(array1.as_ptr(),
                                     lockstep.array1.as_mut_ptr(),
                                     B1::capacity());
            mem::forget(array1);
            ptr::copy_nonoverlapping(array2.as_ptr(),
                                     lockstep.array2.as_mut_ptr(),
                                     B2::capacity());
            mem::forget(array2);
        }
        lockstep.len = len;
        lockstep
    }

    pub fn push(&mut self, item1: A1::Item, item2: A2::Item)
                -> Result<(), OverflowError<A1::Item, A2::Item>> {
        if self.len.as_usize() == A1::capacity() {
            return Err(OverflowError(item1, item2));
        }
        unsafe {
            let p1 = self.array1.as_mut_ptr();
            ptr::write(p1.offset(self.len.as_usize() as isize), item1);
            let p2 = self.array2.as_mut_ptr();
            ptr::write(p2.offset(self.len.as_usize() as isize), item2);
        }
        self.len += One::one();
        Ok(())
    }

    pub fn pop(&mut self) -> Option<(A1::Item, A2::Item)> {
        if self.len == Zero::zero() {
            None
        } else {
            unsafe {
                // Calculate item 1's pointer
                let src1 = self.array1.as_mut_ptr()
                    .offset(self.len.as_usize() as isize);
                // Move item 1 out of the pointer
                let item1 = ptr::read(src1);
                // Calculate item 2's pointer
                let src2 = self.array2.as_mut_ptr()
                    .offset(self.len.as_usize() as isize);
                // Move item 2 out of the pointer
                let item2 = ptr::read(src2);
                // Update length
                self.len -= One::one();
                Some((item1, item2))
            }
        }
    }

    pub fn insert(&mut self, index: usize, item1: A1::Item, item2: A2::Item)
                  -> Result<(), InsertError<A1::Item, A2::Item>> {
        if index > self.len.as_usize() {
            Err(InsertError::OutOfBounds(item1, item2))
        } else if self.len.as_usize() == A1::capacity() {
            Err(InsertError::Overflow(item1, item2))
        } else {
            unsafe {
                // TODO: Tricky math, check indices and such
                let dest1 = self.array1.as_mut_ptr().offset(index as isize);
                ptr::copy(dest1, dest1.offset(1), self.len.as_usize() - index);
                ptr::write(dest1, item1);
                let dest2 = self.array2.as_mut_ptr().offset(index as isize);
                ptr::copy(dest2, dest2.offset(1), self.len.as_usize() - index);
                ptr::write(dest2, item2);
            }
            self.len += One::one();
            Ok(())
        }
    }

    pub fn remove(&mut self, index: usize) -> Option<(A1::Item, A2::Item)> {
        if index >= self.len.as_usize() {
            None
        } else {
            let item1;
            let item2;
            unsafe {
                // Calculate item 1's pointer
                let src1 = self.array1.as_mut_ptr().offset(index as isize);
                // Move item 1 out of the pointer
                item1 = ptr::read(src1);
                // Shift down array 1 down by 1
                ptr::copy(src1.offset(1), src1, self.len.as_usize() - index - 1);
                // Calculate item 2's pointer
                let src2 = self.array2.as_mut_ptr().offset(index as isize);
                // Move item 2 out of the pointer
                item2 = ptr::read(src2);
                // Shift down array 2 down by 1
                ptr::copy(src2.offset(1), src2, self.len.as_usize() - index - 1);
                // Update length
                self.len -= One::one();
            }
            Some((item1, item2))
        }
    }

    pub fn is_empty(&self) -> bool {
        self.len == Zero::zero()
    }

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

    pub fn get(&self, index: usize) -> Option<(&A1::Item, &A2::Item)> {
        if index >= self.len.as_usize() {
            None
        } else {
            let item1 = unsafe {
                &*self.array1.as_ptr().offset(index as isize)
            };
            let item2 = unsafe {
                &*self.array2.as_ptr().offset(index as isize)
            };
            Some((item1, item2))
        }
    }

    pub fn array1(&self) -> &[A1::Item] {
        unsafe {
            let ptr = self.array1.as_ptr();
            let len = self.len.as_usize();
            slice::from_raw_parts(ptr, len)
        }
    }

    pub fn array2(&self) -> &[A2::Item] {
        unsafe {
            let ptr = self.array2.as_ptr();
            let len = self.len.as_usize();
            slice::from_raw_parts(ptr, len)
        }
    }

    pub fn array1_mut(&mut self) -> &mut [A1::Item] {
        unsafe {
            let ptr = self.array1.as_mut_ptr();
            let len = self.len.as_usize();
            slice::from_raw_parts_mut(ptr, len)
        }
    }

    pub fn array2_mut(&mut self) -> &mut [A2::Item] {
        unsafe {
            let ptr = self.array2.as_mut_ptr();
            let len = self.len.as_usize();
            slice::from_raw_parts_mut(ptr, len)
        }
    }

    pub fn capacity(&self) -> usize {
        A1::capacity()
    }
}

impl<A1, A2> Default for LockstepArray<A1, A2> where A1: Array, A2: Array {
    fn default() -> Self {
        Self::new()
    }
}

impl<A1, A2> IntoIterator for LockstepArray<A1, A2> where A1: Array, A2: Array {
    type Item = (A1::Item, A2::Item);
    type IntoIter = IntoIter<A1, A2>;
    fn into_iter(self) -> Self::IntoIter {
        let LockstepArray { len, array1, array2 } = self;
        IntoIter {
            len: len.as_usize(),
            array1: array1,
            array2: array2,
            pos: 0
        }
    }
}

pub struct IntoIter<A1: Array, A2: Array> {
    len: usize,
    array1: NoDrop<A1>,
    array2: NoDrop<A2>,
    pos: usize
}

impl<A1: Array, A2: Array> Iterator for IntoIter<A1, A2> {
    type Item = (A1::Item, A2::Item);
    fn next(&mut self) -> Option<Self::Item> {
        if self.pos == self.len {
            None
        } else {
            unsafe {
                let ptr1 = self.array1.as_mut_ptr().offset(self.pos as isize);
                let item1 = ptr::read(ptr1);
                let ptr2 = self.array2.as_mut_ptr().offset(self.pos as isize);
                let item2 = ptr::read(ptr2);
                self.pos += 1;
                Some((item1, item2))
            }
        }
    }
}

#[test]
fn test_into_iter() {
    let mut locksteparray = LockstepArray::<[u8; 7], [u8; 7]>::new();
    locksteparray.insert(0, 4, 5).unwrap();
    locksteparray.insert(1, 3, 4).unwrap();
    let mut iter = locksteparray.into_iter();
    assert_eq!(iter.next(), Some((4, 5)));
    assert_eq!(iter.next(), Some((3, 4)));
    assert_eq!(iter.next(), None);
}

#[test]
fn test_remove() {
    let mut locksteparray = LockstepArray::<[u8; 7], [u8; 7]>::new();
    locksteparray.push(1, 2).unwrap();
    locksteparray.push(3, 4).unwrap();
    locksteparray.remove(0);
    assert_eq!(locksteparray.get(0), Some((&3, &4)));
    locksteparray.push(5, 6).unwrap();
    locksteparray.remove(1);
    assert_eq!(locksteparray.get(0), Some((&3, &4)));
}

#[test]
fn test_length() {
    let mut locksteparray = LockstepArray::<[u8; 7], [u8; 7]>::new();
    assert_eq!(locksteparray.len(), 0);
    assert!(locksteparray.is_empty());
    locksteparray.insert(0, 4, 5).unwrap();
    assert_eq!(locksteparray.len(), 1);
    locksteparray.insert(1, 3, 4).unwrap();
    assert_eq!(locksteparray.len(), 2);
    locksteparray.pop();
    assert_eq!(locksteparray.len(), 1);
    locksteparray.pop();
    assert_eq!(locksteparray.len(), 0);
    assert!(locksteparray.is_empty());
}

// TODO: Remove when this is detected at compile time.
#[test]
#[should_panic]
fn test_different_sized_arrays() {
    let _ = LockstepArray::<[u8; 2], [u8; 7]>::new();
}
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) COMFOLLOW Chowner Passwd RFILE RFILE's derefer dgid duid

#[macro_use]
extern crate uucore;
pub use uucore::entries::{self, Group, Locate, Passwd};
use uucore::fs::resolve_relative_path;
use uucore::libc::{gid_t, uid_t};
use uucore::perms::{wrap_chown, Verbosity};

use clap::{App, Arg};

use walkdir::WalkDir;

use std::fs::{self, Metadata};
use std::os::unix::fs::MetadataExt;

use std::convert::AsRef;
use std::path::Path;

static ABOUT: &str = "change file owner and group";
static VERSION: &str = env!("CARGO_PKG_VERSION");

static OPT_CHANGES: &str = "changes";
static OPT_DEREFERENCE: &str = "dereference";
static OPT_NO_DEREFERENCE: &str = "no-dereference";
static OPT_FROM: &str = "from";
static OPT_PRESERVE_ROOT: &str = "preserve-root";
static OPT_NO_PRESERVE_ROOT: &str = "no-preserve-root";
static OPT_QUIET: &str = "quiet";
static OPT_RECURSIVE: &str = "recursive";
static OPT_REFERENCE: &str = "reference";
static OPT_SILENT: &str = "silent";
static OPT_TRAVERSE: &str = "H";
static OPT_NO_TRAVERSE: &str = "P";
static OPT_TRAVERSE_EVERY: &str = "L";
static OPT_VERBOSE: &str = "verbose";

static ARG_OWNER: &str = "owner";
static ARG_FILES: &str = "files";

const FTS_COMFOLLOW: u8 = 1;
const FTS_PHYSICAL: u8 = 1 << 1;
const FTS_LOGICAL: u8 = 1 << 2;

fn get_usage() -> String {
    format!(
        "{0} [OPTION]... [OWNER][:[GROUP]] FILE...\n{0} [OPTION]... --reference=RFILE FILE...",
        executable!()
    )
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args.collect_str();

    let usage = get_usage();

    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .arg(
            Arg::with_name(OPT_CHANGES)
                .short("c")
                .long(OPT_CHANGES)
                .help("like verbose but report only when a change is made"),
        )
        .arg(Arg::with_name(OPT_DEREFERENCE).long(OPT_DEREFERENCE).help(
            "affect the referent of each symbolic link (this is the default), rather than the symbolic link itself",
        ))
        .arg(
            Arg::with_name(OPT_NO_DEREFERENCE)
                .short("h")
                .long(OPT_NO_DEREFERENCE)
                .help(
                    "affect symbolic links instead of any referenced file (useful only on systems that can change the ownership of a symlink)",
                ),
        )
        .arg(
            Arg::with_name(OPT_FROM)
                .long(OPT_FROM)
                .help(
                    "change the owner and/or group of each file only if its current owner and/or group match those specified here. Either may be omitted, in which case a match is not required for the omitted attribute",
                )
                .value_name("CURRENT_OWNER:CURRENT_GROUP"),
        )
        .arg(
            Arg::with_name(OPT_PRESERVE_ROOT)
                .long(OPT_PRESERVE_ROOT)
                .help("fail to operate recursively on '/'"),
        )
        .arg(
            Arg::with_name(OPT_NO_PRESERVE_ROOT)
                .long(OPT_NO_PRESERVE_ROOT)
                .help("do not treat '/' specially (the default)"),
        )
        .arg(
            Arg::with_name(OPT_QUIET)
                .long(OPT_QUIET)
                .help("suppress most error messages"),
        )
        .arg(
            Arg::with_name(OPT_RECURSIVE)
                .short("R")
                .long(OPT_RECURSIVE)
                .help("operate on files and directories recursively"),
        )
        .arg(
            Arg::with_name(OPT_REFERENCE)
                .long(OPT_REFERENCE)
                .help("use RFILE's owner and group rather than specifying OWNER:GROUP values")
                .value_name("RFILE")
                .min_values(1),
        )
        .arg(Arg::with_name(OPT_SILENT).short("f").long(OPT_SILENT))
        .arg(
            Arg::with_name(OPT_TRAVERSE)
                .short(OPT_TRAVERSE)
                .help("if a command line argument is a symbolic link to a directory, traverse it")
                .overrides_with_all(&[OPT_TRAVERSE_EVERY, OPT_NO_TRAVERSE]),
        )
        .arg(
            Arg::with_name(OPT_TRAVERSE_EVERY)
                .short(OPT_TRAVERSE_EVERY)
                .help("traverse every symbolic link to a directory encountered")
                .overrides_with_all(&[OPT_TRAVERSE, OPT_NO_TRAVERSE]),
        )
        .arg(
            Arg::with_name(OPT_NO_TRAVERSE)
                .short(OPT_NO_TRAVERSE)
                .help("do not traverse any symbolic links (default)")
                .overrides_with_all(&[OPT_TRAVERSE, OPT_TRAVERSE_EVERY]),
        )
        .arg(
            Arg::with_name(OPT_VERBOSE)
                .long(OPT_VERBOSE)
                .help("output a diagnostic for every file processed"),
        )
        .arg(
            Arg::with_name(ARG_OWNER)
                .multiple(false)
                .takes_value(true)
                .required(true),
        )
        .arg(
            Arg::with_name(ARG_FILES)
                .multiple(true)
                .takes_value(true)
                .required(true)
                .min_values(1),
        )
        .get_matches_from(args);

    /* First arg is the owner/group */
    let owner = matches.value_of(ARG_OWNER).unwrap();

    /* Then the list of files */
    let files: Vec<String> = matches
        .values_of(ARG_FILES)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    let preserve_root = matches.is_present(OPT_PRESERVE_ROOT);

    let mut derefer = if matches.is_present(OPT_NO_DEREFERENCE) {
        1
    } else {
        0
    };

    let mut bit_flag = if matches.is_present(OPT_TRAVERSE) {
        FTS_COMFOLLOW | FTS_PHYSICAL
    } else if matches.is_present(OPT_TRAVERSE_EVERY) {
        FTS_LOGICAL
    } else {
        FTS_PHYSICAL
    };

    let recursive = matches.is_present(OPT_RECURSIVE);
    if recursive {
        if bit_flag == FTS_PHYSICAL {
            if derefer == 1 {
                show_info!("-R --dereference requires -H or -L");
                return 1;
            }
            derefer = 0;
        }
    } else {
        bit_flag = FTS_PHYSICAL;
    }

    let verbosity = if matches.is_present(OPT_CHANGES) {
        Verbosity::Changes
    } else if matches.is_present(OPT_SILENT) || matches.is_present(OPT_QUIET) {
        Verbosity::Silent
    } else if matches.is_present(OPT_VERBOSE) {
        Verbosity::Verbose
    } else {
        Verbosity::Normal
    };

    let filter = if let Some(spec) = matches.value_of(OPT_FROM) {
        match parse_spec(&spec) {
            Ok((Some(uid), None)) => IfFrom::User(uid),
            Ok((None, Some(gid))) => IfFrom::Group(gid),
            Ok((Some(uid), Some(gid))) => IfFrom::UserGroup(uid, gid),
            Ok((None, None)) => IfFrom::All,
            Err(e) => {
                show_info!("{}", e);
                return 1;
            }
        }
    } else {
        IfFrom::All
    };

    let dest_uid: Option<u32>;
    let dest_gid: Option<u32>;
    if let Some(file) = matches.value_of(OPT_REFERENCE) {
        match fs::metadata(&file) {
            Ok(meta) => {
                dest_gid = Some(meta.gid());
                dest_uid = Some(meta.uid());
            }
            Err(e) => {
                show_info!("failed to get attributes of '{}': {}", file, e);
                return 1;
            }
        }
    } else {
        match parse_spec(&owner) {
            Ok((u, g)) => {
                dest_uid = u;
                dest_gid = g;
            }
            Err(e) => {
                show_info!("{}", e);
                return 1;
            }
        }
    }
    let executor = Chowner {
        bit_flag,
        dest_uid,
        dest_gid,
        verbosity,
        recursive,
        dereference: derefer != 0,
        filter,
        preserve_root,
        files,
    };
    executor.exec()
}

fn parse_spec(spec: &str) -> Result<(Option<u32>, Option<u32>), String> {
    let args = spec.split(':').collect::<Vec<_>>();
    let usr_only = args.len() == 1;
    let grp_only = args.len() == 2 && args[0].is_empty() && !args[1].is_empty();
    let usr_grp = args.len() == 2 && !args[0].is_empty() && !args[1].is_empty();

    if usr_only {
        Ok((
            Some(match Passwd::locate(args[0]) {
                Ok(v) => v.uid(),
                _ => return Err(format!("invalid user: '{}'", spec)),
            }),
            None,
        ))
    } else if grp_only {
        Ok((
            None,
            Some(match Group::locate(args[1]) {
                Ok(v) => v.gid(),
                _ => return Err(format!("invalid group: '{}'", spec)),
            }),
        ))
    } else if usr_grp {
        Ok((
            Some(match Passwd::locate(args[0]) {
                Ok(v) => v.uid(),
                _ => return Err(format!("invalid user: '{}'", spec)),
            }),
            Some(match Group::locate(args[1]) {
                Ok(v) => v.gid(),
                _ => return Err(format!("invalid group: '{}'", spec)),
            }),
        ))
    } else {
        Ok((None, None))
    }
}

enum IfFrom {
    All,
    User(u32),
    Group(u32),
    UserGroup(u32, u32),
}

struct Chowner {
    dest_uid: Option<u32>,
    dest_gid: Option<u32>,
    bit_flag: u8,
    verbosity: Verbosity,
    filter: IfFrom,
    files: Vec<String>,
    recursive: bool,
    preserve_root: bool,
    dereference: bool,
}

macro_rules! unwrap {
    ($m:expr, $e:ident, $err:block) => {
        match $m {
            Ok(meta) => meta,
            Err($e) => $err,
        }
    };
}

impl Chowner {
    fn exec(&self) -> i32 {
        let mut ret = 0;
        for f in &self.files {
            ret |= self.traverse(f);
        }
        ret
    }

    fn traverse<P: AsRef<Path>>(&self, root: P) -> i32 {
        let follow_arg = self.dereference || self.bit_flag != FTS_PHYSICAL;
        let path = root.as_ref();
        let meta = match self.obtain_meta(path, follow_arg) {
            Some(m) => m,
            _ => return 1,
        };

        // Prohibit only if:
        // (--preserve-root and -R present) &&
        // (
        //     (argument is not symlink && resolved to be '/') ||
        //     (argument is symlink && should follow argument && resolved to be '/')
        // )
        if self.recursive && self.preserve_root {
            let may_exist = if follow_arg {
                path.canonicalize().ok()
            } else {
                let real = resolve_relative_path(path);
                if real.is_dir() {
                    Some(real.canonicalize().expect("failed to get real path"))
                } else {
                    Some(real.into_owned())
                }
            };

            if let Some(p) = may_exist {
                if p.parent().is_none() {
                    show_info!("it is dangerous to operate recursively on '/'");
                    show_info!("use --no-preserve-root to override this failsafe");
                    return 1;
                }
            }
        }

        let ret = if self.matched(meta.uid(), meta.gid()) {
            match wrap_chown(
                path,
                &meta,
                self.dest_uid,
                self.dest_gid,
                follow_arg,
                self.verbosity.clone(),
            ) {
                Ok(n) => {
                    if n != "" {
                        show_info!("{}", n);
                    }
                    0
                }
                Err(e) => {
                    if self.verbosity != Verbosity::Silent {
                        show_info!("{}", e);
                    }
                    1
                }
            }
        } else {
            0
        };

        if !self.recursive {
            ret
        } else {
            ret | self.dive_into(&root)
        }
    }

    fn dive_into<P: AsRef<Path>>(&self, root: P) -> i32 {
        let mut ret = 0;
        let root = root.as_ref();
        let follow = self.dereference || self.bit_flag & FTS_LOGICAL != 0;
        for entry in WalkDir::new(root).follow_links(follow).min_depth(1) {
            let entry = unwrap!(entry, e, {
                ret = 1;
                show_info!("{}", e);
                continue;
            });
            let path = entry.path();
            let meta = match self.obtain_meta(path, follow) {
                Some(m) => m,
                _ => {
                    ret = 1;
                    continue;
                }
            };

            if !self.matched(meta.uid(), meta.gid()) {
                continue;
            }

            ret = match wrap_chown(
                path,
                &meta,
                self.dest_uid,
                self.dest_gid,
                follow,
                self.verbosity.clone(),
            ) {
                Ok(n) => {
                    if n != "" {
                        show_info!("{}", n);
                    }
                    0
                }
                Err(e) => {
                    if self.verbosity != Verbosity::Silent {
                        show_info!("{}", e);
                    }
                    1
                }
            }
        }
        ret
    }

    fn obtain_meta<P: AsRef<Path>>(&self, path: P, follow: bool) -> Option<Metadata> {
        use self::Verbosity::*;
        let path = path.as_ref();
        let meta = if follow {
            unwrap!(path.metadata(), e, {
                match self.verbosity {
                    Silent => (),
                    _ => show_info!("cannot access '{}': {}", path.display(), e),
                }
                return None;
            })
        } else {
            unwrap!(path.symlink_metadata(), e, {
                match self.verbosity {
                    Silent => (),
                    _ => show_info!("cannot dereference '{}': {}", path.display(), e),
                }
                return None;
            })
        };
        Some(meta)
    }

    #[inline]
    fn matched(&self, uid: uid_t, gid: gid_t) -> bool {
        match self.filter {
            IfFrom::All => true,
            IfFrom::User(u) => u == uid,
            IfFrom::Group(g) => g == gid,
            IfFrom::UserGroup(u, g) => u == uid && g == gid,
        }
    }
}
<commit_msg>separate options into modules for chown<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) COMFOLLOW Chowner Passwd RFILE RFILE's derefer dgid duid

#[macro_use]
extern crate uucore;
pub use uucore::entries::{self, Group, Locate, Passwd};
use uucore::fs::resolve_relative_path;
use uucore::libc::{gid_t, uid_t};
use uucore::perms::{wrap_chown, Verbosity};

use clap::{App, Arg};

use walkdir::WalkDir;

use std::fs::{self, Metadata};
use std::os::unix::fs::MetadataExt;

use std::convert::AsRef;
use std::path::Path;

static ABOUT: &str = "change file owner and group";
static VERSION: &str = env!("CARGO_PKG_VERSION");

pub mod options {
    pub mod verbosity {
        pub static CHANGES: &str = "changes";
        pub static QUIET: &str = "quiet";
        pub static SILENT: &str = "silent";
        pub static VERBOSE: &str = "verbose";
    }
    pub mod preserve_root {
        pub static PRESERVE: &str = "preserve-root";
        pub static NO_PRESERVE: &str = "no-preserve-root";
    }
    pub mod dereference {
        pub static DEREFERENCE: &str = "dereference";
        pub static NO_DEREFERENCE: &str = "no-dereference"; // not actually read?
    }
    pub static FROM: &str = "from";
    pub static RECURSIVE: &str = "recursive"; // TODO(felipel) recursive, reference, traverse related?
    pub mod traverse {
        pub static TRAVERSE: &str = "H";
        pub static NO_TRAVERSE: &str = "P";
        pub static EVERY: &str = "L";
    }
    pub static REFERENCE: &str = "reference";
}

static ARG_OWNER: &str = "owner";
static ARG_FILES: &str = "files";

const FTS_COMFOLLOW: u8 = 1;
const FTS_PHYSICAL: u8 = 1 << 1;
const FTS_LOGICAL: u8 = 1 << 2;

fn get_usage() -> String {
    format!(
        "{0} [OPTION]... [OWNER][:[GROUP]] FILE...\n{0} [OPTION]... --reference=RFILE FILE...",
        executable!()
    )
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args.collect_str();

    let usage = get_usage();

    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .arg(
            Arg::with_name(options::verbosity::CHANGES)
                .short("c")
                .long(options::verbosity::CHANGES)
                .help("like verbose but report only when a change is made"),
        )
        .arg(Arg::with_name(options::dereference::DEREFERENCE).long(options::dereference::DEREFERENCE).help(
            "affect the referent of each symbolic link (this is the default), rather than the symbolic link itself",
        ))
        .arg(
            Arg::with_name(options::dereference::NO_DEREFERENCE)
                .short("h")
                .long(options::dereference::NO_DEREFERENCE)
                .help(
                    "affect symbolic links instead of any referenced file (useful only on systems that can change the ownership of a symlink)",
                ),
        )
        .arg(
            Arg::with_name(options::FROM)
                .long(options::FROM)
                .help(
                    "change the owner and/or group of each file only if its current owner and/or group match those specified here. Either may be omitted, in which case a match is not required for the omitted attribute",
                )
                .value_name("CURRENT_OWNER:CURRENT_GROUP"),
        )
        .arg(
            Arg::with_name(options::preserve_root::PRESERVE)
                .long(options::preserve_root::PRESERVE)
                .help("fail to operate recursively on '/'"),
        )
        .arg(
            Arg::with_name(options::preserve_root::NO_PRESERVE)
                .long(options::preserve_root::NO_PRESERVE)
                .help("do not treat '/' specially (the default)"),
        )
        .arg(
            Arg::with_name(options::verbosity::QUIET)
                .long(options::verbosity::QUIET)
                .help("suppress most error messages"),
        )
        .arg(
            Arg::with_name(options::RECURSIVE)
                .short("R")
                .long(options::RECURSIVE)
                .help("operate on files and directories recursively"),
        )
        .arg(
            Arg::with_name(options::REFERENCE)
                .long(options::REFERENCE)
                .help("use RFILE's owner and group rather than specifying OWNER:GROUP values")
                .value_name("RFILE")
                .min_values(1),
        )
        .arg(Arg::with_name(options::verbosity::SILENT).short("f").long(options::verbosity::SILENT))
        .arg(
            Arg::with_name(options::traverse::TRAVERSE)
                .short(options::traverse::TRAVERSE)
                .help("if a command line argument is a symbolic link to a directory, traverse it")
                .overrides_with_all(&[options::traverse::EVERY, options::traverse::NO_TRAVERSE]),
        )
        .arg(
            Arg::with_name(options::traverse::EVERY)
                .short(options::traverse::EVERY)
                .help("traverse every symbolic link to a directory encountered")
                .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::NO_TRAVERSE]),
        )
        .arg(
            Arg::with_name(options::traverse::NO_TRAVERSE)
                .short(options::traverse::NO_TRAVERSE)
                .help("do not traverse any symbolic links (default)")
                .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::EVERY]),
        )
        .arg(
            Arg::with_name(options::verbosity::VERBOSE)
                .long(options::verbosity::VERBOSE)
                .help("output a diagnostic for every file processed"),
        )
        .arg(
            Arg::with_name(ARG_OWNER)
                .multiple(false)
                .takes_value(true)
                .required(true),
        )
        .arg(
            Arg::with_name(ARG_FILES)
                .multiple(true)
                .takes_value(true)
                .required(true)
                .min_values(1),
        )
        .get_matches_from(args);

    /* First arg is the owner/group */
    let owner = matches.value_of(ARG_OWNER).unwrap();

    /* Then the list of files */
    let files: Vec<String> = matches
        .values_of(ARG_FILES)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    let preserve_root = matches.is_present(options::preserve_root::PRESERVE);

    let mut derefer = if matches.is_present(options::dereference::NO_DEREFERENCE) {
        1
    } else {
        0
    };

    let mut bit_flag = if matches.is_present(options::traverse::TRAVERSE) {
        FTS_COMFOLLOW | FTS_PHYSICAL
    } else if matches.is_present(options::traverse::EVERY) {
        FTS_LOGICAL
    } else {
        FTS_PHYSICAL
    };

    let recursive = matches.is_present(options::RECURSIVE);
    if recursive {
        if bit_flag == FTS_PHYSICAL {
            if derefer == 1 {
                show_info!("-R --dereference requires -H or -L");
                return 1;
            }
            derefer = 0;
        }
    } else {
        bit_flag = FTS_PHYSICAL;
    }

    let verbosity = if matches.is_present(options::verbosity::CHANGES) {
        Verbosity::Changes
    } else if matches.is_present(options::verbosity::SILENT)
        || matches.is_present(options::verbosity::QUIET)
    {
        Verbosity::Silent
    } else if matches.is_present(options::verbosity::VERBOSE) {
        Verbosity::Verbose
    } else {
        Verbosity::Normal
    };

    let filter = if let Some(spec) = matches.value_of(options::FROM) {
        match parse_spec(&spec) {
            Ok((Some(uid), None)) => IfFrom::User(uid),
            Ok((None, Some(gid))) => IfFrom::Group(gid),
            Ok((Some(uid), Some(gid))) => IfFrom::UserGroup(uid, gid),
            Ok((None, None)) => IfFrom::All,
            Err(e) => {
                show_info!("{}", e);
                return 1;
            }
        }
    } else {
        IfFrom::All
    };

    let dest_uid: Option<u32>;
    let dest_gid: Option<u32>;
    if let Some(file) = matches.value_of(options::REFERENCE) {
        match fs::metadata(&file) {
            Ok(meta) => {
                dest_gid = Some(meta.gid());
                dest_uid = Some(meta.uid());
            }
            Err(e) => {
                show_info!("failed to get attributes of '{}': {}", file, e);
                return 1;
            }
        }
    } else {
        match parse_spec(&owner) {
            Ok((u, g)) => {
                dest_uid = u;
                dest_gid = g;
            }
            Err(e) => {
                show_info!("{}", e);
                return 1;
            }
        }
    }
    let executor = Chowner {
        bit_flag,
        dest_uid,
        dest_gid,
        verbosity,
        recursive,
        dereference: derefer != 0,
        filter,
        preserve_root,
        files,
    };
    executor.exec()
}

fn parse_spec(spec: &str) -> Result<(Option<u32>, Option<u32>), String> {
    let args = spec.split(':').collect::<Vec<_>>();
    let usr_only = args.len() == 1;
    let grp_only = args.len() == 2 && args[0].is_empty() && !args[1].is_empty();
    let usr_grp = args.len() == 2 && !args[0].is_empty() && !args[1].is_empty();

    if usr_only {
        Ok((
            Some(match Passwd::locate(args[0]) {
                Ok(v) => v.uid(),
                _ => return Err(format!("invalid user: '{}'", spec)),
            }),
            None,
        ))
    } else if grp_only {
        Ok((
            None,
            Some(match Group::locate(args[1]) {
                Ok(v) => v.gid(),
                _ => return Err(format!("invalid group: '{}'", spec)),
            }),
        ))
    } else if usr_grp {
        Ok((
            Some(match Passwd::locate(args[0]) {
                Ok(v) => v.uid(),
                _ => return Err(format!("invalid user: '{}'", spec)),
            }),
            Some(match Group::locate(args[1]) {
                Ok(v) => v.gid(),
                _ => return Err(format!("invalid group: '{}'", spec)),
            }),
        ))
    } else {
        Ok((None, None))
    }
}

enum IfFrom {
    All,
    User(u32),
    Group(u32),
    UserGroup(u32, u32),
}

struct Chowner {
    dest_uid: Option<u32>,
    dest_gid: Option<u32>,
    bit_flag: u8,
    verbosity: Verbosity,
    filter: IfFrom,
    files: Vec<String>,
    recursive: bool,
    preserve_root: bool,
    dereference: bool,
}

macro_rules! unwrap {
    ($m:expr, $e:ident, $err:block) => {
        match $m {
            Ok(meta) => meta,
            Err($e) => $err,
        }
    };
}

impl Chowner {
    fn exec(&self) -> i32 {
        let mut ret = 0;
        for f in &self.files {
            ret |= self.traverse(f);
        }
        ret
    }

    fn traverse<P: AsRef<Path>>(&self, root: P) -> i32 {
        let follow_arg = self.dereference || self.bit_flag != FTS_PHYSICAL;
        let path = root.as_ref();
        let meta = match self.obtain_meta(path, follow_arg) {
            Some(m) => m,
            _ => return 1,
        };

        // Prohibit only if:
        // (--preserve-root and -R present) &&
        // (
        //     (argument is not symlink && resolved to be '/') ||
        //     (argument is symlink && should follow argument && resolved to be '/')
        // )
        if self.recursive && self.preserve_root {
            let may_exist = if follow_arg {
                path.canonicalize().ok()
            } else {
                let real = resolve_relative_path(path);
                if real.is_dir() {
                    Some(real.canonicalize().expect("failed to get real path"))
                } else {
                    Some(real.into_owned())
                }
            };

            if let Some(p) = may_exist {
                if p.parent().is_none() {
                    show_info!("it is dangerous to operate recursively on '/'");
                    show_info!("use --no-preserve-root to override this failsafe");
                    return 1;
                }
            }
        }

        let ret = if self.matched(meta.uid(), meta.gid()) {
            match wrap_chown(
                path,
                &meta,
                self.dest_uid,
                self.dest_gid,
                follow_arg,
                self.verbosity.clone(),
            ) {
                Ok(n) => {
                    if n != "" {
                        show_info!("{}", n);
                    }
                    0
                }
                Err(e) => {
                    if self.verbosity != Verbosity::Silent {
                        show_info!("{}", e);
                    }
                    1
                }
            }
        } else {
            0
        };

        if !self.recursive {
            ret
        } else {
            ret | self.dive_into(&root)
        }
    }

    fn dive_into<P: AsRef<Path>>(&self, root: P) -> i32 {
        let mut ret = 0;
        let root = root.as_ref();
        let follow = self.dereference || self.bit_flag & FTS_LOGICAL != 0;
        for entry in WalkDir::new(root).follow_links(follow).min_depth(1) {
            let entry = unwrap!(entry, e, {
                ret = 1;
                show_info!("{}", e);
                continue;
            });
            let path = entry.path();
            let meta = match self.obtain_meta(path, follow) {
                Some(m) => m,
                _ => {
                    ret = 1;
                    continue;
                }
            };

            if !self.matched(meta.uid(), meta.gid()) {
                continue;
            }

            ret = match wrap_chown(
                path,
                &meta,
                self.dest_uid,
                self.dest_gid,
                follow,
                self.verbosity.clone(),
            ) {
                Ok(n) => {
                    if n != "" {
                        show_info!("{}", n);
                    }
                    0
                }
                Err(e) => {
                    if self.verbosity != Verbosity::Silent {
                        show_info!("{}", e);
                    }
                    1
                }
            }
        }
        ret
    }

    fn obtain_meta<P: AsRef<Path>>(&self, path: P, follow: bool) -> Option<Metadata> {
        use self::Verbosity::*;
        let path = path.as_ref();
        let meta = if follow {
            unwrap!(path.metadata(), e, {
                match self.verbosity {
                    Silent => (),
                    _ => show_info!("cannot access '{}': {}", path.display(), e),
                }
                return None;
            })
        } else {
            unwrap!(path.symlink_metadata(), e, {
                match self.verbosity {
                    Silent => (),
                    _ => show_info!("cannot dereference '{}': {}", path.display(), e),
                }
                return None;
            })
        };
        Some(meta)
    }

    #[inline]
    fn matched(&self, uid: uid_t, gid: gid_t) -> bool {
        match self.filter {
            IfFrom::All => true,
            IfFrom::User(u) => u == uid,
            IfFrom::Group(g) => g == gid,
            IfFrom::UserGroup(u, g) => u == uid && g == gid,
        }
    }
}
<|endoftext|>