From 1164b9e1187a95d097dd373facfb03a0cbd5563a Mon Sep 17 00:00:00 2001 From: Wim Hueskes Date: Mon, 1 Aug 2016 00:03:47 +0200 Subject: [PATCH] od: fix file byte offset for non-octal types removed binary offset, added no offset. --- src/od/od.rs | 64 ++++++++++++++++++++++++------------------------ tests/test_od.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 32 deletions(-) diff --git a/src/od/od.rs b/src/od/od.rs index a7bdec8a6..efe83cd8c 100644 --- a/src/od/od.rs +++ b/src/od/od.rs @@ -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) -> i32 { let mut opts = getopts::Options::new(); @@ -62,27 +62,27 @@ pub fn uumain(args: Vec) -> 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) -> 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) -> Result { 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) -> Result { '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(""), } } diff --git a/tests/test_od.rs b/tests/test_od.rs index 1c513e28e..96196d9e5 100644 --- a/tests/test_od.rs +++ b/tests/test_od.rs @@ -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); +}