diff --git a/src/od/formatteriteminfo.rs b/src/od/formatteriteminfo.rs new file mode 100644 index 000000000..c6974a172 --- /dev/null +++ b/src/od/formatteriteminfo.rs @@ -0,0 +1,12 @@ +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum FormatWriter { + IntWriter(fn(u64, usize, usize) -> String), + FloatWriter(fn(f64) -> String), +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct FormatterItemInfo { + pub byte_size: usize, + pub print_width: usize, + pub formatter: FormatWriter, +} diff --git a/src/od/od.rs b/src/od/od.rs index 6ee2566d9..ac7984dde 100644 --- a/src/od/od.rs +++ b/src/od/od.rs @@ -18,6 +18,7 @@ extern crate uucore; mod multifilereader; mod byteorder_io; +mod formatteriteminfo; mod prn_int; mod prn_char; mod prn_float; @@ -30,6 +31,7 @@ use multifilereader::*; use prn_int::*; use prn_char::*; use prn_float::*; +use formatteriteminfo::*; //This is available in some versions of std, but not all that we target. macro_rules! hashmap { @@ -155,68 +157,29 @@ pub fn uumain(args: Vec) -> i32 { }) .collect::>(); - // At the moment, char (-a & -c)formats need the driver to set up a - // line by inserting a different # of of spaces at the start. - struct OdFormater { - writer: FormatWriter, - offmarg: usize, - }; - let oct = OdFormater { - writer: FormatWriter::IntWriter(format_item_oct), offmarg: 2 - }; - let hex = OdFormater { - writer: FormatWriter::IntWriter(format_item_hex), offmarg: 2 - }; - let dec_u = OdFormater { - writer: FormatWriter::IntWriter(format_item_dec_u), offmarg: 2 - }; - let dec_s = OdFormater { - writer: FormatWriter::IntWriter(format_item_dec_s), offmarg: 2 - }; - let a_char = OdFormater { - writer: FormatWriter::IntWriter(format_item_a), offmarg: 1 - }; - let c_char = OdFormater { - writer: FormatWriter::IntWriter(format_item_c), offmarg: 1 - }; - let flo32 = OdFormater { - writer: FormatWriter::FloatWriter(format_item_flo32), offmarg: 0 - }; - let flo64 = OdFormater { - writer: FormatWriter::FloatWriter(format_item_flo64), offmarg: 0 - }; - - fn mkfmt(itembytes: usize, fmtspec: &OdFormater) -> OdFormat { - OdFormat { - itembytes: itembytes, - writer: fmtspec.writer, - offmarg: fmtspec.offmarg, - } - } - // TODO: -t fmts let known_formats = hashmap![ - "a" => (1, &a_char), - "B" => (2, &oct) , - "b" => (1, &oct), - "c" => (1, &c_char), - "D" => (4, &dec_u), - "e" => (8, &flo64), - "F" => (8, &flo64), - "f" => (4, &flo32), - "H" => (4, &hex), - "X" => (4, &hex) , - "o" => (2, &oct), - "x" => (2, &hex), - "h" => (2, &hex), + "a" => FORMAT_ITEM_A, + "B" => FORMAT_ITEM_OCT16, + "b" => FORMAT_ITEM_OCT8, + "c" => FORMAT_ITEM_C, + "D" => FORMAT_ITEM_DEC32U, + "e" => FORMAT_ITEM_F64, + "F" => FORMAT_ITEM_F64, + "f" => FORMAT_ITEM_F32, + "H" => FORMAT_ITEM_HEX32, + "X" => FORMAT_ITEM_HEX32, + "o" => FORMAT_ITEM_OCT16, + "x" => FORMAT_ITEM_HEX16, + "h" => FORMAT_ITEM_HEX16, - "I" => (2, &dec_s), - "L" => (2, &dec_s), - "i" => (2, &dec_s), + "I" => FORMAT_ITEM_DEC16S, + "L" => FORMAT_ITEM_DEC16S, + "i" => FORMAT_ITEM_DEC16S, - "O" => (4, &oct), - "s" => (2, &dec_u) - ]; + "O" => FORMAT_ITEM_OCT32, + "s" => FORMAT_ITEM_DEC16U + ]; let mut formats = Vec::new(); @@ -224,14 +187,13 @@ pub fn uumain(args: Vec) -> i32 { match known_formats.get(flag) { None => {} // not every option is a format Some(r) => { - let (itembytes, fmtspec) = *r; - formats.push(mkfmt(itembytes, fmtspec)) + formats.push(*r) } } } if formats.is_empty() { - formats.push(mkfmt(2, &oct)); // 2 byte octal is the default + formats.push(FORMAT_ITEM_OCT16); // 2 byte octal is the default } let mut line_bytes = match matches.opt_default("w", "32") { @@ -243,7 +205,7 @@ pub fn uumain(args: Vec) -> i32 { } } }; - let min_bytes = formats.iter().fold(2, |max, next| cmp::max(max, next.itembytes)); + let min_bytes = formats.iter().fold(2, |max, next| cmp::max(max, next.byte_size)); if line_bytes % min_bytes != 0 { show_warning!("invalid width {}; using {} instead", line_bytes, min_bytes); line_bytes = min_bytes; @@ -255,7 +217,7 @@ pub fn uumain(args: Vec) -> i32 { } fn odfunc(line_bytes: usize, input_offset_base: &Radix, byte_order: ByteOrder, - fnames: &[InputSource], formats: &[OdFormat], output_duplicates: bool) -> i32 { + fnames: &[InputSource], formats: &[FormatterItemInfo], output_duplicates: bool) -> i32 { let mut mf = MultifileReader::new(fnames); let mut addr = 0; @@ -308,19 +270,17 @@ fn odfunc(line_bytes: usize, input_offset_base: &Radix, byte_order: ByteOrder, } } -fn print_bytes(byte_order: ByteOrder, bytes: &[u8], length: usize, prefix: &str, formats: &[OdFormat]) { +fn print_bytes(byte_order: ByteOrder, bytes: &[u8], length: usize, prefix: &str, formats: &[FormatterItemInfo]) { let mut first = true; // First line of a multi-format raster. for f in formats { let mut output_text = String::new(); - output_text.push_str(&format!("{:>width$}", "", width = f.offmarg));// 4 spaces after offset - we print 2 more before each word - let mut b = 0; while b < length { - let nextb = b + f.itembytes; - match f.writer { + let nextb = b + f.byte_size; + match f.formatter { FormatWriter::IntWriter(func) => { - let p: u64 = match f.itembytes { + let p: u64 = match f.byte_size { 1 => { bytes[b] as u64 } @@ -333,19 +293,19 @@ fn print_bytes(byte_order: ByteOrder, bytes: &[u8], length: usize, prefix: &str, 8 => { byte_order.read_u64(&bytes[b..nextb]) } - _ => { panic!("Invalid itembytes: {}", f.itembytes); } + _ => { panic!("Invalid byte_size: {}", f.byte_size); } }; - output_text.push_str(&func(p, f.itembytes)); + output_text.push_str(&func(p, f.byte_size, f.print_width)); } FormatWriter::FloatWriter(func) => { - let p: f64 = match f.itembytes { + let p: f64 = match f.byte_size { 4 => { byte_order.read_f32(&bytes[b..nextb]) as f64 } 8 => { byte_order.read_f64(&bytes[b..nextb]) } - _ => { panic!("Invalid itembytes: {}", f.itembytes); } + _ => { panic!("Invalid byte_size: {}", f.byte_size); } }; output_text.push_str(&func(p)); } @@ -400,15 +360,3 @@ fn print_with_radix(r: &Radix, x: usize) -> String{ Radix::Binary => format!("{:07b}", x) } } - -#[derive(Clone, Copy)] -enum FormatWriter { - IntWriter(fn(u64, usize) -> String), - FloatWriter(fn(f64) -> String), -} - -struct OdFormat { - itembytes: usize, - writer: FormatWriter, - offmarg: usize, -} diff --git a/src/od/prn_char.rs b/src/od/prn_char.rs index b631becfe..a9663c26a 100644 --- a/src/od/prn_char.rs +++ b/src/od/prn_char.rs @@ -1,3 +1,16 @@ +use formatteriteminfo::*; + +pub static FORMAT_ITEM_A: FormatterItemInfo = FormatterItemInfo { + byte_size: 1, + print_width: 3, + formatter: FormatWriter::IntWriter(format_item_a), +}; + +pub static FORMAT_ITEM_C: FormatterItemInfo = FormatterItemInfo { + byte_size: 1, + print_width: 3, + formatter: FormatWriter::IntWriter(format_item_c), +}; // TODO: multi-byte chars // Quoth the man page: Multi-byte characters are displayed in the area corresponding to the first byte of the character. The remaining bytes are shown as `**'. @@ -24,7 +37,7 @@ static A_CHRS : [&'static str; 160] = "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b", "9c", "9d", "9e", "9f"]; -pub fn format_item_a(p: u64, _: usize) -> String { +pub fn format_item_a(p: u64, _: usize, _: usize) -> String { // itembytes == 1 let b = (p & 0xff) as u8; format!("{:>4}", A_CHRS.get(b as usize).unwrap_or(&"?") // XXX od dose not actually do this, it just prints the byte @@ -51,7 +64,7 @@ static C_CHRS : [&'static str; 127] = [ "x", "y", "z", "{", "|", "}", "~" ]; -pub fn format_item_c(p: u64, _: usize) -> String { +pub fn format_item_c(p: u64, _: usize, _: usize) -> String { // itembytes == 1 let b = (p & 0xff) as usize; diff --git a/src/od/prn_float.rs b/src/od/prn_float.rs index 93a4c9ee6..4ecc63200 100644 --- a/src/od/prn_float.rs +++ b/src/od/prn_float.rs @@ -1,6 +1,20 @@ use std::num::FpCategory; use std::f32; use std::f64; +use formatteriteminfo::*; + +pub static FORMAT_ITEM_F32: FormatterItemInfo = FormatterItemInfo { + byte_size: 4, + print_width: 14, + formatter: FormatWriter::FloatWriter(format_item_flo32), +}; + +pub static FORMAT_ITEM_F64: FormatterItemInfo = FormatterItemInfo { + byte_size: 8, + print_width: 24, + formatter: FormatWriter::FloatWriter(format_item_flo64), +}; + pub fn format_item_flo32(f: f64) -> String { format!(" {}", format_flo32(f as f32)) diff --git a/src/od/prn_int.rs b/src/od/prn_int.rs index 24bdee939..27cdcfdde 100644 --- a/src/od/prn_int.rs +++ b/src/od/prn_int.rs @@ -1,24 +1,125 @@ -// TODO: use some sort of byte iterator, instead of passing bytes in u64 -pub fn format_item_oct(p: u64, itembytes: usize) -> String { - let itemwidth = 3 * itembytes; - let itemspace = 4 * itembytes - itemwidth; +use formatteriteminfo::*; - format!("{:>itemspace$}{:0width$o}", - "", +pub static FORMAT_ITEM_OCT8: FormatterItemInfo = FormatterItemInfo { + byte_size: 1, + print_width: 3, + formatter: FormatWriter::IntWriter(format_item_oct), +}; + +pub static FORMAT_ITEM_OCT16: FormatterItemInfo = FormatterItemInfo { + byte_size: 2, + print_width: 6, + formatter: FormatWriter::IntWriter(format_item_oct), +}; + +pub static FORMAT_ITEM_OCT32: FormatterItemInfo = FormatterItemInfo { + byte_size: 4, + print_width: 12, + formatter: FormatWriter::IntWriter(format_item_oct), +}; + +#[allow(dead_code)] +pub static FORMAT_ITEM_OCT64: FormatterItemInfo = FormatterItemInfo { + byte_size: 8, + print_width: 24, + formatter: FormatWriter::IntWriter(format_item_oct), +}; + +#[allow(dead_code)] +pub static FORMAT_ITEM_HEX8: FormatterItemInfo = FormatterItemInfo { + byte_size: 1, + print_width: 2, + formatter: FormatWriter::IntWriter(format_item_hex), +}; + +pub static FORMAT_ITEM_HEX16: FormatterItemInfo = FormatterItemInfo { + byte_size: 2, + print_width: 4, + formatter: FormatWriter::IntWriter(format_item_hex), +}; + +pub static FORMAT_ITEM_HEX32: FormatterItemInfo = FormatterItemInfo { + byte_size: 4, + print_width: 8, + formatter: FormatWriter::IntWriter(format_item_hex), +}; + +#[allow(dead_code)] +pub static FORMAT_ITEM_HEX64: FormatterItemInfo = FormatterItemInfo { + byte_size: 8, + print_width: 16, + formatter: FormatWriter::IntWriter(format_item_hex), +}; + + +#[allow(dead_code)] +pub static FORMAT_ITEM_DEC8U: FormatterItemInfo = FormatterItemInfo { + byte_size: 1, + print_width: 3, + formatter: FormatWriter::IntWriter(format_item_dec_u), +}; + +pub static FORMAT_ITEM_DEC16U: FormatterItemInfo = FormatterItemInfo { + byte_size: 2, + print_width: 5, + formatter: FormatWriter::IntWriter(format_item_dec_u), +}; + +pub static FORMAT_ITEM_DEC32U: FormatterItemInfo = FormatterItemInfo { + byte_size: 4, + print_width: 10, + formatter: FormatWriter::IntWriter(format_item_dec_u), +}; + +#[allow(dead_code)] +pub static FORMAT_ITEM_DEC64U: FormatterItemInfo = FormatterItemInfo { + byte_size: 8, + print_width: 19, + formatter: FormatWriter::IntWriter(format_item_dec_u), +}; + + +#[allow(dead_code)] +pub static FORMAT_ITEM_DEC8S: FormatterItemInfo = FormatterItemInfo { + byte_size: 1, + print_width: 4, + formatter: FormatWriter::IntWriter(format_item_dec_s), +}; + +pub static FORMAT_ITEM_DEC16S: FormatterItemInfo = FormatterItemInfo { + byte_size: 2, + print_width: 6, + formatter: FormatWriter::IntWriter(format_item_dec_s), +}; + +#[allow(dead_code)] +pub static FORMAT_ITEM_DEC32S: FormatterItemInfo = FormatterItemInfo { + byte_size: 4, + print_width: 11, + formatter: FormatWriter::IntWriter(format_item_dec_s), +}; + +#[allow(dead_code)] +pub static FORMAT_ITEM_DEC64S: FormatterItemInfo = FormatterItemInfo { + byte_size: 8, + print_width: 20, + formatter: FormatWriter::IntWriter(format_item_dec_s), +}; + + +// TODO: use some sort of byte iterator, instead of passing bytes in u64 +pub fn format_item_oct(p: u64, _: usize, print_width: usize) -> String { + + format!(" {:0width$o}", p, - width = itemwidth, - itemspace = itemspace) + width = print_width) } -pub fn format_item_hex(p: u64, itembytes: usize) -> String { - let itemwidth = 2 * itembytes; - let itemspace = 4 * itembytes - itemwidth; +pub fn format_item_hex(p: u64, _: usize, print_width: usize) -> String { - format!("{:>itemspace$}{:0width$x}", - "", + format!(" {:0width$x}", p, - width = itemwidth, - itemspace = itemspace) + width = print_width) } @@ -28,12 +129,12 @@ fn sign_extend(item: u64, itembytes: usize) -> i64{ } -pub fn format_item_dec_s(p: u64, itembytes: usize) -> String { +pub fn format_item_dec_s(p: u64, itembytes: usize, print_width: usize) -> String { // sign extend - let s = sign_extend(p,itembytes); - format!("{:totalwidth$}", s, totalwidth = 4 * itembytes) + let s = sign_extend(p, itembytes); + format!(" {:width$}", s, width = print_width) } -pub fn format_item_dec_u(p: u64, itembytes: usize) -> String { - format!("{:totalwidth$}", p, totalwidth = 4 * itembytes) +pub fn format_item_dec_u(p: u64, _: usize, print_width: usize) -> String { + format!(" {:width$}", p, width = print_width) } diff --git a/tests/test_od.rs b/tests/test_od.rs index a6dd2046f..a7bfc3d5e 100644 --- a/tests/test_od.rs +++ b/tests/test_od.rs @@ -11,8 +11,8 @@ use self::unindent::*; // octal dump of 'abcdefghijklmnopqrstuvwxyz\n' static ALPHA_OUT: &'static str = " - 0000000 061141 062143 063145 064147 065151 066153 067155 070157 - 0000020 071161 072163 073165 074167 075171 000012 + 0000000 061141 062143 063145 064147 065151 066153 067155 070157 + 0000020 071161 072163 073165 074167 075171 000012 0000033 "; @@ -134,10 +134,10 @@ fn test_multiple_formats() { assert_empty_stderr!(result); assert!(result.success); assert_eq!(result.stdout, unindent(" - 0000000 a b c d e f g h i j k l m n o p - 141 142 143 144 145 146 147 150 151 152 153 154 155 156 157 160 - 0000020 q r s t u v w x y z \\n - 161 162 163 164 165 166 167 170 171 172 012 + 0000000 a b c d e f g h i j k l m n o p + 141 142 143 144 145 146 147 150 151 152 153 154 155 156 157 160 + 0000020 q r s t u v w x y z \\n + 161 162 163 164 165 166 167 170 171 172 012 0000033 ")); @@ -155,7 +155,7 @@ fn test_dec() { 0x00u8,0x80u8, 0x01u8,0x80u8,]; let expected_output = unindent(" - 0000000 0 1 2 3 32767 -32768 -32767 + 0000000 0 1 2 3 32767 -32768 -32767 0000016 "); let result = new_ucmd!().arg("--endian=little").arg("-i").run_piped_stdin(&input[..]); @@ -172,7 +172,7 @@ fn test_hex16(){ let input : [u8; 9] = [ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xff]; let expected_output = unindent(" - 0000000 2301 6745 ab89 efcd 00ff + 0000000 2301 6745 ab89 efcd 00ff 0000011 "); let result = new_ucmd!().arg("--endian=little").arg("-x").run_piped_stdin(&input[..]); @@ -188,7 +188,7 @@ fn test_hex32(){ let input : [u8; 9] = [ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xff]; let expected_output = unindent(" - 0000000 67452301 efcdab89 000000ff + 0000000 67452301 efcdab89 000000ff 0000011 "); let result = new_ucmd!().arg("--endian=little").arg("-X").run_piped_stdin(&input[..]); @@ -261,8 +261,8 @@ fn test_width(){ let input : [u8; 8] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; let expected_output = unindent(" - 0000000 000000 000000 - 0000004 000000 000000 + 0000000 000000 000000 + 0000004 000000 000000 0000010 "); @@ -278,8 +278,8 @@ fn test_invalid_width(){ let input : [u8; 4] = [0x00, 0x00, 0x00, 0x00]; let expected_output = unindent(" - 0000000 000000 - 0000002 000000 + 0000000 000000 + 0000002 000000 0000004 "); @@ -295,8 +295,8 @@ fn test_width_without_value(){ let input : [u8; 40] = [0 ; 40]; let expected_output = unindent(" - 0000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 - 0000040 000000 000000 000000 000000 + 0000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 + 0000040 000000 000000 000000 000000 0000050 "); @@ -312,11 +312,11 @@ fn test_suppress_duplicates(){ let input = [0u8 ; 41]; let expected_output = unindent(" - 0000000 000000000000 - 0000 0000 + 0000000 000000000000 + 0000 0000 * - 0000050 000000000000 - 0000 + 0000050 000000000000 + 0000 0000051 "); @@ -335,8 +335,8 @@ fn test_big_endian() { let expected_output = unindent(" 0000000 -2.0000000000000000 -2.0000000 0 - c0000000 00000000 - c000 0000 0000 0000 + c0000000 00000000 + c000 0000 0000 0000 0000010 "); let result = new_ucmd!().arg("--endian=big").arg("-F").arg("-f").arg("-X").arg("-x").run_piped_stdin(&input[..]);