Skip to content

Commit e45d963

Browse files
authored
Merge pull request #157 from rustcoreutils/dd
dd work
2 parents 1aad392 + f92935d commit e45d963

File tree

2 files changed

+85
-47
lines changed

2 files changed

+85
-47
lines changed

file/src/dd.rs

Lines changed: 60 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,17 @@ enum AsciiConv {
8080
IBM,
8181
}
8282

83+
#[derive(Debug)]
84+
enum Conversion {
85+
Ascii(AsciiConv),
86+
Lcase,
87+
Ucase,
88+
Swab,
89+
Block,
90+
Unblock,
91+
Sync,
92+
}
93+
8394
#[derive(Debug)]
8495
struct Config {
8596
ifile: String,
@@ -91,15 +102,9 @@ struct Config {
91102
seek: usize,
92103
skip: usize,
93104
count: usize,
94-
95-
ascii: Option<AsciiConv>,
96-
block: Option<bool>,
97-
lcase: bool,
98-
ucase: bool,
99-
swab: bool,
105+
conversions: Vec<Conversion>,
100106
noerror: bool,
101107
notrunc: bool,
102-
sync: bool,
103108
}
104109

105110
impl Config {
@@ -114,14 +119,9 @@ impl Config {
114119
seek: 0,
115120
skip: 0,
116121
count: 0,
117-
ascii: None,
118-
block: None,
119-
lcase: false,
120-
ucase: false,
121-
swab: false,
122+
conversions: Vec::new(),
122123
noerror: false,
123124
notrunc: false,
124-
sync: false,
125125
}
126126
}
127127
}
@@ -169,17 +169,22 @@ fn convert_ucase(data: &mut [u8]) {
169169
}
170170

171171
fn apply_conversions(data: &mut [u8], config: &Config) {
172-
if let Some(ascii_conv) = &config.ascii {
173-
convert_ascii(data, ascii_conv);
174-
}
175-
if config.swab {
176-
convert_swab(data);
177-
}
178-
if config.lcase {
179-
convert_lcase(data);
180-
}
181-
if config.ucase {
182-
convert_ucase(data);
172+
for conversion in &config.conversions {
173+
match conversion {
174+
Conversion::Ascii(ascii_conv) => convert_ascii(data, ascii_conv),
175+
Conversion::Lcase => convert_lcase(data),
176+
Conversion::Ucase => convert_ucase(data),
177+
Conversion::Swab => convert_swab(data),
178+
Conversion::Block => {
179+
todo!()
180+
} // implement block conversion
181+
Conversion::Unblock => {
182+
todo!()
183+
} // implement unblock conversion
184+
Conversion::Sync => {
185+
todo!()
186+
} // implement sync conversion
187+
}
183188
}
184189
}
185190

@@ -200,20 +205,21 @@ fn copy_convert_file(config: &Config) -> Result<(), Box<dyn std::error::Error>>
200205
let mut ibuf = vec![0u8; config.ibs];
201206
let mut obuf = vec![0u8; config.obs];
202207

208+
// Skip the specified number of bytes
209+
let mut skipped = 0;
210+
while skipped < config.skip {
211+
let bytes_to_skip = std::cmp::min(config.skip - skipped, config.ibs);
212+
let n = ifile.read(&mut ibuf[..bytes_to_skip])?;
213+
if n == 0 {
214+
break;
215+
}
216+
skipped += n;
217+
}
218+
203219
let mut count = 0;
204-
let mut skip = config.skip;
205220
let mut seek = config.seek;
206221

207222
loop {
208-
if skip > 0 {
209-
let n = ifile.read(&mut ibuf)?;
210-
if n == 0 {
211-
break;
212-
}
213-
skip -= n;
214-
continue;
215-
}
216-
217223
if seek > 0 {
218224
let n = ifile.read(&mut ibuf)?;
219225
if n == 0 {
@@ -250,23 +256,30 @@ fn copy_convert_file(config: &Config) -> Result<(), Box<dyn std::error::Error>>
250256

251257
fn parse_conv_list(config: &mut Config, s: &str) -> Result<(), Box<dyn std::error::Error>> {
252258
for convstr in s.split(",") {
253-
match convstr {
254-
"ascii" => config.ascii = Some(AsciiConv::Ascii),
255-
"ebcdic" => config.ascii = Some(AsciiConv::EBCDIC),
256-
"ibm" => config.ascii = Some(AsciiConv::IBM),
257-
"block" => config.block = Some(true),
258-
"unblock" => config.block = Some(false),
259-
"lcase" => config.lcase = true,
260-
"ucase" => config.ucase = true,
261-
"swab" => config.swab = true,
262-
"noerror" => config.noerror = true,
263-
"notrunc" => config.notrunc = true,
264-
"sync" => config.sync = true,
259+
let conversion = match convstr {
260+
"ascii" => Conversion::Ascii(AsciiConv::Ascii),
261+
"ebcdic" => Conversion::Ascii(AsciiConv::EBCDIC),
262+
"ibm" => Conversion::Ascii(AsciiConv::IBM),
263+
"block" => Conversion::Block,
264+
"unblock" => Conversion::Unblock,
265+
"lcase" => Conversion::Lcase,
266+
"ucase" => Conversion::Ucase,
267+
"swab" => Conversion::Swab,
268+
"sync" => Conversion::Sync,
269+
"noerror" => {
270+
config.noerror = true;
271+
continue;
272+
}
273+
"notrunc" => {
274+
config.notrunc = true;
275+
continue;
276+
}
265277
_ => {
266278
eprintln!("{}: {}", gettext("invalid conv option"), convstr);
267279
return Err("invalid conv option".into());
268280
}
269-
}
281+
};
282+
config.conversions.push(conversion);
270283
}
271284
Ok(())
272285
}

file/tests/dd-tests.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,28 @@ fn test_lcase_conversion() {
178178
expected_exit_code: 0,
179179
});
180180
}
181+
182+
#[test]
183+
fn test_skip_n() {
184+
let input_file_path = get_test_file_path("dd.ascii");
185+
186+
let mut input_file = File::open(input_file_path).expect("Unable to open input test file");
187+
let mut input_data = Vec::new();
188+
input_file
189+
.read_to_end(&mut input_data)
190+
.expect("Unable to read input test file");
191+
192+
let expected_output = b"world! {[ $&chars ]}\nAlas, poor Yorick, I knew him well.\n";
193+
194+
run_test_u8(TestPlanU8 {
195+
cmd: String::from("dd"),
196+
args: vec![
197+
String::from("ibs=1"),
198+
String::from("skip=7"), // Adjusting skip to 7 bytes to reach the correct output
199+
],
200+
stdin_data: input_data,
201+
expected_out: expected_output.to_vec(),
202+
expected_err: Vec::new(),
203+
expected_exit_code: 0,
204+
});
205+
}

0 commit comments

Comments
 (0)