1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 03:27:44 +00:00

od: fix file byte offset for non-octal types

removed binary offset, added no offset.
This commit is contained in:
Wim Hueskes 2016-08-01 00:03:47 +02:00
parent 24fb6d66c4
commit 1164b9e118
2 changed files with 94 additions and 32 deletions

View file

@ -45,8 +45,8 @@ macro_rules! hashmap {
static VERSION: &'static str = env!("CARGO_PKG_VERSION");
const MAX_BYTES_PER_UNIT: usize = 8;
#[derive(Debug)]
enum Radix { Decimal, Hexadecimal, Octal, Binary }
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum Radix { Decimal, Hexadecimal, Octal, NoPrefix }
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = getopts::Options::new();
@ -62,27 +62,27 @@ pub fn uumain(args: Vec<String>) -> i32 {
("output strings of at least BYTES graphic chars. 3 is assumed when \
BYTES is not specified."),
"BYTES");
opts.optflag("a", "", "named characters, ignoring high-order bit");
opts.optflag("b", "", "octal bytes");
opts.optflag("c", "", "ASCII characters or backslash escapes");
opts.optflag("d", "", "unsigned decimal 2-byte units");
opts.optflag("D", "", "unsigned decimal 4-byte units");
opts.optflag("o", "", "unsigned decimal 2-byte units");
opts.optflagmulti("a", "", "named characters, ignoring high-order bit");
opts.optflagmulti("b", "", "octal bytes");
opts.optflagmulti("c", "", "ASCII characters or backslash escapes");
opts.optflagmulti("d", "", "unsigned decimal 2-byte units");
opts.optflagmulti("D", "", "unsigned decimal 4-byte units");
opts.optflagmulti("o", "", "unsigned decimal 2-byte units");
opts.optflag("I", "", "decimal 2-byte units");
opts.optflag("L", "", "decimal 2-byte units");
opts.optflag("i", "", "decimal 2-byte units");
opts.optflag("x", "", "hexadecimal 2-byte units");
opts.optflag("h", "", "hexadecimal 2-byte units");
opts.optflagmulti("I", "", "decimal 2-byte units");
opts.optflagmulti("L", "", "decimal 2-byte units");
opts.optflagmulti("i", "", "decimal 2-byte units");
opts.optflagmulti("x", "", "hexadecimal 2-byte units");
opts.optflagmulti("h", "", "hexadecimal 2-byte units");
opts.optflag("O", "", "octal 4-byte units");
opts.optflag("s", "", "decimal 4-byte units");
opts.optflag("X", "", "hexadecimal 4-byte units");
opts.optflag("H", "", "hexadecimal 4-byte units");
opts.optflagmulti("O", "", "octal 4-byte units");
opts.optflagmulti("s", "", "decimal 4-byte units");
opts.optflagmulti("X", "", "hexadecimal 4-byte units");
opts.optflagmulti("H", "", "hexadecimal 4-byte units");
opts.optflag("e", "", "floating point double precision (64-bit) units");
opts.optflag("f", "", "floating point single precision (32-bit) units");
opts.optflag("F", "", "floating point double precision (64-bit) units");
opts.optflagmulti("e", "", "floating point double precision (64-bit) units");
opts.optflagmulti("f", "", "floating point single precision (32-bit) units");
opts.optflagmulti("F", "", "floating point double precision (64-bit) units");
opts.optopt("t", "format", "select output format or formats", "TYPE");
opts.optflag("v", "output-duplicates", "do not use * to mark line suppression");
@ -216,10 +216,10 @@ pub fn uumain(args: Vec<String>) -> i32 {
let output_duplicates = matches.opt_present("v");
odfunc(line_bytes, &input_offset_base, byte_order, &inputs, &formats[..], output_duplicates)
odfunc(line_bytes, input_offset_base, byte_order, &inputs, &formats[..], output_duplicates)
}
fn odfunc(line_bytes: usize, input_offset_base: &Radix, byte_order: ByteOrder,
fn odfunc(line_bytes: usize, input_offset_base: Radix, byte_order: ByteOrder,
fnames: &[InputSource], formats: &[FormatterItemInfo], output_duplicates: bool) -> i32 {
let mut mf = MultifileReader::new(fnames);
@ -270,7 +270,9 @@ fn odfunc(line_bytes: usize, input_offset_base: &Radix, byte_order: ByteOrder,
match mf.f_read(bytes.as_mut_slice()) {
Ok(0) => {
print!("{}\n", print_with_radix(input_offset_base, addr)); // print final offset
if input_offset_base != Radix::NoPrefix {
print!("{}\n", print_with_radix(input_offset_base, addr)); // print final offset
}
break;
}
Ok(n) => {
@ -381,7 +383,7 @@ fn parse_radix(radix_str: Option<String>) -> Result<Radix, &'static str> {
Some(s) => {
let st = s.into_bytes();
if st.len() != 1 {
Err("Radix must be one of [d, o, b, x]\n")
Err("Radix must be one of [d, o, n, x]\n")
} else {
let radix: char = *(st.get(0)
.expect("byte string of length 1 lacks a 0th elem")) as char;
@ -389,22 +391,20 @@ fn parse_radix(radix_str: Option<String>) -> Result<Radix, &'static str> {
'd' => Ok(Radix::Decimal),
'x' => Ok(Radix::Hexadecimal),
'o' => Ok(Radix::Octal),
'b' => Ok(Radix::Binary),
_ => Err("Radix must be one of [d, o, b, x]\n")
'n' => Ok(Radix::NoPrefix),
_ => Err("Radix must be one of [d, o, n, x]\n")
}
}
}
}
}
fn print_with_radix(r: &Radix, x: usize) -> String{
// TODO(keunwoo): field widths should be based on sizeof(x), or chosen dynamically based on the
// expected range of address values. Binary in particular is not great here.
match *r {
fn print_with_radix(r: Radix, x: usize) -> String{
match r {
Radix::Decimal => format!("{:07}", x),
Radix::Hexadecimal => format!("{:07X}", x),
Radix::Hexadecimal => format!("{:06X}", x),
Radix::Octal => format!("{:07o}", x),
Radix::Binary => format!("{:07b}", x)
Radix::NoPrefix => String::from(""),
}
}

View file

@ -410,3 +410,65 @@ fn test_maxuint(){
assert!(result.success);
assert_eq!(result.stdout, expected_output);
}
#[test]
fn test_hex_offset(){
let input = [0u8 ; 0x1F];
let expected_output = unindent("
000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
000010 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00001F
");
let result = new_ucmd!().arg("-Ax").arg("-X").arg("-X").run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
}
#[test]
fn test_dec_offset(){
let input = [0u8 ; 19];
let expected_output = unindent("
0000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
0000016 00000000
00000000
0000019
");
let result = new_ucmd!().arg("-Ad").arg("-X").arg("-X").run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
}
#[test]
fn test_no_offset(){
let input = [0u8 ; 31];
const LINE: &'static str = " 00000000 00000000 00000000 00000000\n";
let expected_output = [LINE, LINE, LINE, LINE].join("");
let result = new_ucmd!().arg("-An").arg("-X").arg("-X").run_piped_stdin(&input[..]);
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
}
#[test]
fn test_invalid_offset(){
let input = [0u8 ; 4];
let result = new_ucmd!().arg("-Ab").run_piped_stdin(&input[..]);
assert!(!result.success);
}