From d64053771c263b5fbbaab71200b9ab983f6681dc Mon Sep 17 00:00:00 2001 From: Tom Milligan Date: Mon, 7 Oct 2019 19:20:02 +0100 Subject: [PATCH] hexyl: add display offset option --- src/bin/hexyl.rs | 30 +++++++++++++++++++++++------- src/lib.rs | 43 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/src/bin/hexyl.rs b/src/bin/hexyl.rs index 8621bd2..0f4a970 100644 --- a/src/bin/hexyl.rs +++ b/src/bin/hexyl.rs @@ -69,6 +69,14 @@ fn run() -> Result<(), Box> { .possible_values(&["unicode", "ascii", "none"]) .default_value("unicode") .help("Whether to draw a border with unicode or ASCII characters, or none at all"), + ) + .arg( + Arg::with_name("display_offset") + .short("o") + .long("display-offset") + .takes_value(true) + .value_name("OFFSET") + .help("Add OFFSET to the displayed file position."), ); let matches = app.get_matches_safe()?; @@ -82,13 +90,7 @@ fn run() -> Result<(), Box> { let length_arg = matches.value_of("length").or(matches.value_of("bytes")); - if let Some(length) = length_arg.and_then(|n| { - if n.starts_with("0x") { - u64::from_str_radix(n.trim_start_matches("0x"), 16).ok() - } else { - n.parse::().ok() - } - }) { + if let Some(length) = length_arg.and_then(parse_hex_or_int) { reader = Box::new(reader.take(length)); } @@ -106,6 +108,11 @@ fn run() -> Result<(), Box> { let squeeze = !matches.is_present("nosqueezing"); + let display_offset = matches + .value_of("display_offset") + .and_then(parse_hex_or_int) + .unwrap_or(0); + // Set up Ctrl-C handler let cancelled = Arc::new(AtomicBool::new(false)); let c = cancelled.clone(); @@ -119,6 +126,7 @@ fn run() -> Result<(), Box> { let mut stdout_lock = stdout.lock(); let mut printer = Printer::new(&mut stdout_lock, show_color, border_style, squeeze); + printer.display_offset(display_offset as usize); printer.print_all(&mut reader, Some(cancelled))?; Ok(()) @@ -148,3 +156,11 @@ fn main() { std::process::exit(1); } } + +fn parse_hex_or_int(n: &str) -> Option { + if n.starts_with("0x") { + u64::from_str_radix(n.trim_start_matches("0x"), 16).ok() + } else { + n.parse::().ok() + } +} diff --git a/src/lib.rs b/src/lib.rs index cb8f7ca..c97ae5c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -155,6 +155,7 @@ pub struct Printer<'a, Writer: Write> { byte_hex_table: Vec, byte_char_table: Vec, squeezer: Squeezer, + display_offset: usize, } impl<'a, Writer: Write> Printer<'a, Writer> { @@ -193,9 +194,15 @@ impl<'a, Writer: Write> Printer<'a, Writer> { }) .collect(), squeezer: Squeezer::new(use_squeeze), + display_offset: 0, } } + pub fn display_offset(&mut self, display_offset: usize) -> &mut Self { + self.display_offset = display_offset; + self + } + pub fn header(&mut self) { if let Some(border_elements) = self.border_style.header_elems() { let h = border_elements.horizontal_line; @@ -241,7 +248,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> { } let style = COLOR_OFFSET.normal(); - let byte_index = format!("{:08x}", self.idx - 1); + let byte_index = format!("{:08x}", (self.idx - 1) + self.display_offset); let formatted_string = if self.show_color { format!("{}", style.paint(byte_index)) } else { @@ -456,19 +463,45 @@ mod tests { #[test] fn empty_file_passes() { let input = io::empty(); - let expected_string = "┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐ + let expected_string = + "┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐ └────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘ -".to_owned(); +" + .to_owned(); assert_print_all_output(input, expected_string); } #[test] fn short_input_passes() { let input = io::Cursor::new(b"spam"); - let expected_string = "┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐ + let expected_string = + "┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐ │00000000│ 73 70 61 6d ┊ │spam ┊ │ └────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘ -".to_owned(); +" + .to_owned(); assert_print_all_output(input, expected_string); } + + #[test] + fn display_offset() { + let input = io::Cursor::new(b"spamspamspamspamspam"); + let expected_string = + "┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐ +│deadbeef│ 73 70 61 6d 73 70 61 6d ┊ 73 70 61 6d 73 70 61 6d │spamspam┊spamspam│ +│deadbeff│ 73 70 61 6d ┊ │spam ┊ │ +└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘ +" + .to_owned(); + + let mut output = vec![]; + let mut printer: Printer> = + Printer::new(&mut output, false, BorderStyle::Unicode, true); + printer.display_offset(0xdeadbeef); + + printer.print_all(input, None).unwrap(); + + let actual_string: &str = str::from_utf8(&output).unwrap(); + assert_eq!(actual_string, expected_string) + } }