<commit_before>#![deny(warnings)]
extern crate coreutils;
extern crate extra;

use std::env;
use std::fs::File;
use std::io::{stderr, stdout, Read, Write};
use std::time::Instant;
use std::process::exit;
use coreutils::{ArgParser, to_human_readable_string};
use extra::option::OptionalExt;
use extra::io::fail;

const MAN_PAGE: &'static str = /* @MANSTART{du} */ r#"
NAME
    dd - copy a file

SYNOPSIS
    dd [ -h | --help ] if=[FILE] of=[FILE]

DESCRIPTION
    The dd tool copies from a file to another file in 512-byte block sizes

OPTIONS
    -h
    --help
        display this help and exit

    bs=n
        set input and output block size to n bytes
    count=n
        copy only n blocks
    if=file
        read from file instead of standard input
    of=file
        write output to file instead of standard out

"#; /* @MANEND */

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();

    let mut parser = ArgParser::new(5)
        .add_flag(&["h", "help"])
        .add_setting_default("bs", "512")
        .add_setting_default("count", "-1")
        .add_setting("if")
        .add_setting("of");
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    } else if !parser.found("if") {
        fail("missing if argument", &mut stderr);
    } else if !parser.found("of") {
        fail("missing of argument", &mut stderr);
    } 

    let bs: usize = parser.get_setting("bs").unwrap().parse::<usize>().unwrap();
    let count = parser.get_setting("count").unwrap().parse::<i32>().unwrap();

    let in_path: String = parser.get_setting("if").unwrap();
    let out_path = parser.get_setting("of").unwrap();
    let status = 1;

    let mut input = File::open(in_path).expect("dd: failed to open if");
    let mut output = File::create(out_path).expect("dd: failed to open of");

    let mut in_recs = 0;
    let mut in_extra = 0;
    let mut out_recs = 0;
    let mut out_extra = 0;
    let mut out_total = 0;
    let mut running = true;
    let mut buffer = vec![0; bs];
    let mut last_print = 0;
    let mut last_print_out = 0;
    let start = Instant::now();
    while running {
        let in_count = input.read(&mut buffer).expect("dd: failed to read if");
        if in_count < bs {
            if in_count > 0 {<commit_msg>Add support for stdin and stdout for dd<commit_after>#![deny(warnings)]
extern crate coreutils;
extern crate extra;

use std::env;
use std::fs::File;
use std::io::{self, stderr, stdin, stdout, Read, Write};
use std::time::Instant;
use std::process::exit;
use coreutils::{ArgParser, to_human_readable_string};
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{du} */ r#"
NAME
    dd - copy a file

SYNOPSIS
    dd [ -h | --help ] if=[FILE] of=[FILE]

DESCRIPTION
    The dd tool copies from a file to another file in 512-byte block sizes

OPTIONS
    -h
    --help
        display this help and exit

    bs=n
        set input and output block size to n bytes
    count=n
        copy only n blocks
    if=file
        read from file instead of standard input
    of=file
        write output to file instead of standard out

"#; /* @MANEND */

enum Input<'a> {
    File(File),
    Standard(io::StdinLock<'a>)
}

impl<'a> io::Read for Input<'a> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            Input::File(ref mut f) => f.read(buf),
            Input::Standard(ref mut s) => s.read(buf),
        }
    }
}

enum Output<'a> {
    File(File),
    Standard(io::StdoutLock<'a>)
}

impl<'a> io::Write for Output<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match *self {
            Output::File(ref mut f) => f.write(buf),
            Output::Standard(ref mut s) => s.write(buf),
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        match *self {
            Output::File(ref mut f) => f.flush(),
            Output::Standard(ref mut s) => s.flush(),
        }
    }
}

fn main() {
    let stdin = stdin();
    let stdin = stdin.lock();
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();

    let mut parser = ArgParser::new(5)
        .add_flag(&["h", "help"])
        .add_setting_default("bs", "512")
        .add_setting_default("count", "-1")
        .add_setting("if")
        .add_setting("of");
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    } 

    let bs: usize = parser.get_setting("bs").unwrap().parse::<usize>().unwrap();
    let count = parser.get_setting("count").unwrap().parse::<i32>().unwrap();

    let mut input = match parser.found("if") {
        true => {
            let path = parser.get_setting("if").unwrap();
            Input::File(File::open(path).expect("dd: failed to open if"))
        },
        false => Input::Standard(stdin)
    };

    let mut output = match parser.found("of") {
        true => {
            let path = parser.get_setting("of").unwrap();
            Output::File(File::create(path).expect("dd: failed to open of"))
        },
        false => Output::Standard(stdout)
    };

    let status = 1;
    let mut in_recs = 0;
    let mut in_extra = 0;
    let mut out_recs = 0;
    let mut out_extra = 0;
    let mut out_total = 0;
    let mut running = true;
    let mut buffer = vec![0; bs];
    let mut last_print = 0;
    let mut last_print_out = 0;
    let start = Instant::now();
    while running {
        let in_count = input.read(&mut buffer).expect("dd: failed to read if");
        if in_count < bs {
            if in_count > 0 {
{'fraction_non_alphanumeric': 0.15433585684790088, 'fraction_numerical': 0.007570543702684102, 'mean_word_length': 2.5706388206388207, 'pattern_counts': {'":': 0, '<': 20, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '565431', 'n_tokens_mistral': 1958, 'n_tokens_neox': 1911, 'n_words': 545}