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
161
162
163
164
165
166
167
168
169
170
171
//! # dd: convert and copy a file  
//!
//! ## SYNOPSIS         
//! dd \[OPERAND\]...
//! dd OPTION
//! ## DESCRIPTION         
//! Copy a file converting and formatting according to the operands.
//! ## [`opts`]
//!
//! - **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::flags::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::flags::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::flags::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]:
//! N and BYTES may be followed by the following multiplicative suffixes:
//! - **B** = 1
//! - **K** = 1024
//! - **M**: K*K = 1024²
//! - **G**: M*K = 1024³
//! - **T**:  G*K = 1024⁴
//! - **P**: T*K = 1024⁵
//! - **Z**: P*K = 1024⁶
//! - **KB**: 10⁶
//! - **MB**: 10⁹
//! - **GB**: 10¹²
//! - **TB**: 10¹⁵
//! - **ZB**: 10¹⁸

//! ### [`CONV`][opts::flags::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;
/// configuration and parsing
pub mod opts;
/// structs and enum for success and failure
pub mod results;

use io::{conv::Converter, read::Reader, write::Writer};
use opts::{Mode, Opts};
use results::{Result, Success};

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

#[cfg(test)]
/// integration tests for `dd`;
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<E>(o: &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::from_opts(&stdout, &o)?;
    let c = Converter::new(&o)?;
    let mut err = if o.status == opts::StatusLevel::Progress {
        Some(err)
    } else {
        None
    };

    match o.mode {
        Mode::Block(n) => io::copy::block(r, &mut w, c, &mut err, n),
        Mode::Unblock(n) => io::copy::unblock(r, &mut w, c, &mut err, n),
        Mode::Standard => io::copy::standard(r, &mut w, c, &mut err),
    }
}