1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
//! # dd: convert and copy a file  
//!
//! ## SYNOPSIS         
//! dd \[OPERAND\]...
//! dd OPTION
//! ## DESCRIPTION         
//! Copy a file converting and formatting according to the operands.
//!
//! ## [`opts`]
//! Note: the parsing of numeric arguments is a little unusual and allows for
//! numeric suffixes. See the documentation of [opts::number] and
//! [opts::number::units];
//!
//! - **bs**=BYTES: read and write up to BYTES bytes at a time (default: 512).
//!   - **overrides ibs and obs**
//!
//! - **cbs**=BYTES: convert BYTES bytes at a time
//!
//! - **conv**=[`CONVS`][opts::Conv]: convert the file as per the coma
//!   separated symbol list
//!
//! - **count**=N: copy only N input blocks
//!
//! - **ibs**=BYTES: read up to BYTES bytes at a time (default: 512)
//!
//! - **if**=FILE: read from FILE instead of stdin
//!
//! - **iflag**=[`FLAGS`][opts::In]: read as per the comma separated   symbol
//!   list
//!
//! - **obs**=BYTES: write BYTES bytes at a time (default: 512)
//!
//! - **of**=FILE: write to FILE instead of stdout
//!
//! - **oflag**=[`FLAGS`][opts::Out]: write as per the comma separated   symbol
//!   list
//!
//! - **seek**=N: skip N obs-sized blocks at start of output
//!
//! - **skip**=N: skip N ibs-sized blocks at start of input
//!
//! - **status=[LEVEL][opts::StatusLevel]**: the level of information to print
//!   to stderr
//!
//!    none: suppresses everything but error messages,
//!    progress //! - **shows** periodic transfer statistics
//!    noxfer: suppresses the final transfer statistics,
//!
//!
//! ### [Units][opts::number::units]:

//! ### [`CONV`][opts::Conv]
//! Each CONV symbol may be:

//! 
//! - **ascii**  from EBCDIC to ASCII

//! 
//! - **ebcdic** from ASCII to EBCDIC

//! 
//! - **ibm**    from ASCII to alternate EBCDIC

//! 
//! - **block**  pad newline-terminated records with spaces to cbs-size

//! 
//! - **unblock** replace trailing spaces in cbs-size records with newline

//! 
//! - **lcase**  change upper case to lower case

//! 
//! - **ucase**  change lower case to upper case

//! 
//! - **sparse** try to seek rather than write the output for NUL input blocks

//! 
//! - **swab**   swap every pair of input bytes

//! 
//! - **sync**   pad every input block with NULs to ibs-size; when used with
//!   block or unblock, pad with spaces rather than NULs

//! 
//! - **excl**   fail if the output file already exists

//! 
//! - **nocreat** do not create the output file

//! 
//! - **notrunc** do not truncate the output file

//! 
//! - **noerror** continue after read errors

//! 
//! - **fdatasync**
//! physically write output file data before finishing
//! - **fsync**  likewise, but also write metadata

//! ### SIGNALS
//! Sending a USR1 signal to a running 'dd' process makes it print I/O
//! statistics to standard error and then resume copying.
//!
//!
//! ### OPTIONS
//! --help display this help and exit
//! --version
//! output version information and exit
//! ### AUTHOR         
//! Originally Written by Paul Rubin, David MacKenzie, and Stuart Kemp.
//! Clone written _only_ by looking at man page by Efron Licht
//! input, output, and encoding

pub mod io;
pub mod opts;
pub mod units;
use io::{Converter, ErrHandler, Reader, Writer};
pub use results::{Result, Success};

mod results;

#[cfg(test)]
extern crate tempfile;
#[macro_use]
extern crate bitflags;
extern crate encoding8;

#[cfg(test)]
mod tests;

/// The dd utility copies the standard input to the standard output.  Input data
/// is read and written in n-byte blocks (default `512`).  If input reads are
/// short, input from multiple reads are aggregated to form the output block.
/// When finished, dd displays the number of complete and partial input and
/// output blocks and truncated input records to the standard error output.
pub fn dd(o: &opts::Opts) -> Result<Success> {
    let stderr = std::io::stderr();
    let lock = stderr.lock();
    dd_pipe_err(o, lock)
}

/// dd, piping standard error to E
pub fn dd_pipe_err<E>(o: &opts::Opts, err: E) -> Result<Success>
where
    E: std::io::Write, // in practice, this is always stderr
{
    let (stdin, stdout) = (std::io::stdin(), std::io::stdout());
    let r = Reader::new(&stdin, o)?;
    let mut w = Writer::new(&stdout, o)?;
    let c = Converter::new(o)?;
    let e = ErrHandler::new(err, o);
    match o.mode {
        opts::Mode::Block(n) => io::copy::block(r, &mut w, c, e, n),
        opts::Mode::Unblock(n) => io::copy::unblock(r, &mut w, c, e, n),
        opts::Mode::Standard => io::copy::standard(r, &mut w, c, e),
    }
}