From d5d645fc486e9dccb7c6e9bca0852d842d3911b5 Mon Sep 17 00:00:00 2001 From: Sharif Haason Date: Sun, 27 Nov 2022 17:11:21 -0500 Subject: [PATCH 01/15] Add `Base` to `Printer` --- src/lib.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index ab7b80c..3812cca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,13 @@ use std::io::{self, BufReader, Read, Write}; use anstyle::{AnsiColor, Reset}; +pub enum Base { + Binary, + Octal, + Decimal, + Hexadecimal, +} + #[derive(PartialEq, Eq)] #[repr(usize)] enum ByteColor { @@ -162,6 +169,7 @@ pub struct PrinterBuilder<'a, Writer: Write> { use_squeeze: bool, panels: u64, group_bytes: u8, + base: Base, } impl<'a, Writer: Write> PrinterBuilder<'a, Writer> { @@ -175,6 +183,7 @@ impl<'a, Writer: Write> PrinterBuilder<'a, Writer> { use_squeeze: true, panels: 2, group_bytes: 1, + base: Base::Hexadecimal, } } @@ -213,6 +222,11 @@ impl<'a, Writer: Write> PrinterBuilder<'a, Writer> { self } + pub fn with_base(mut self, base: Base) -> Self { + self.base = base; + self + } + pub fn build(self) -> Printer<'a, Writer> { Printer::new( self.writer, @@ -223,6 +237,7 @@ impl<'a, Writer: Write> PrinterBuilder<'a, Writer> { self.use_squeeze, self.panels, self.group_bytes, + self.base, ) } } @@ -250,6 +265,8 @@ pub struct Printer<'a, Writer: Write> { squeeze_byte: usize, /// The number of octets per group. group_bytes: u8, + /// The number of digits used to write the base. + base_digits: u8, } impl<'a, Writer: Write> Printer<'a, Writer> { @@ -262,6 +279,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> { use_squeeze: bool, panels: u64, group_bytes: u8, + base: Base, ) -> Printer<'a, Writer> { Printer { idx: 0, @@ -298,6 +316,12 @@ impl<'a, Writer: Write> Printer<'a, Writer> { panels, squeeze_byte: 0x00, group_bytes, + base_digits: match base { + Base::Binary => 8, + Base::Octal => 3, + Base::Decimal => 3, + Base::Hexadecimal => 2, + }, } } From 85fa75ba677d32433b2ef95e3118258f6d124ca3 Mon Sep 17 00:00:00 2001 From: Sharif Haason Date: Sun, 27 Nov 2022 17:11:55 -0500 Subject: [PATCH 02/15] Differentiate format on base --- src/lib.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3812cca..357f25f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -299,11 +299,18 @@ impl<'a, Writer: Write> Printer<'a, Writer> { Reset.render().to_string(), ], border_style, - byte_hex_panel: (0u8..=u8::MAX).map(|i| format!("{:02x}", i)).collect(), + byte_hex_panel: (0u8..=u8::MAX) + .map(|i| match base { + Base::Binary => format!("{i:08b}"), + Base::Octal => format!("{i:03o}"), + Base::Decimal => format!("{i:03}"), + Base::Hexadecimal => format!("{i:02x}"), + }) + .collect(), byte_char_panel: (0u8..=u8::MAX) .map(|i| format!("{}", Byte(i).as_char())) .collect(), - byte_hex_panel_g: (0u8..=u8::MAX).map(|i| format!("{:02x}", i)).collect(), + byte_hex_panel_g: (0u8..=u8::MAX).map(|i| format!("{i:02x}")).collect(), byte_char_panel_g: (0u8..=u8::MAX) .map(|i| format!("{}", Byte(i).as_char())) .collect(), From 7f7b88a914bf2abf61cb2731c39500f1f3224ca2 Mon Sep 17 00:00:00 2001 From: Sharif Haason Date: Sun, 27 Nov 2022 17:13:36 -0500 Subject: [PATCH 03/15] Adjust tests --- src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 357f25f..1efae64 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -709,6 +709,7 @@ mod tests { true, 2, 1, + Base::Hexadecimal, ); printer.print_all(input).unwrap(); @@ -762,6 +763,7 @@ mod tests { true, 2, 1, + Base::Hexadecimal, ); printer.display_offset(0xdeadbeef); @@ -794,6 +796,7 @@ mod tests { true, 4, 1, + Base::Hexadecimal, ); printer.print_all(input).unwrap(); @@ -852,6 +855,7 @@ mod tests { true, 3, 1, + Base::Hexadecimal, ); printer.print_all(input).unwrap(); From ec61c2a789f4f1ea36606cdce4b551e90a6709eb Mon Sep 17 00:00:00 2001 From: Sharif Haason Date: Sun, 27 Nov 2022 17:14:30 -0500 Subject: [PATCH 04/15] Print header only if non-empty --- src/lib.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 1efae64..e7431e7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -572,13 +572,15 @@ impl<'a, Writer: Write> Printer<'a, Writer> { let mut buf = BufReader::new(reader); - self.print_header()?; let leftover = loop { // read a maximum of 8 * self.panels bytes from the reader if let Ok(n) = buf.read(&mut self.line_buf) { if n > 0 && n < 8 * self.panels as usize { // if less are read, that indicates end of file after + if is_empty { + self.print_header()?; is_empty = false; + } // perform second check on read if let Ok(0) = buf.read(&mut self.line_buf[n..]) { @@ -595,7 +597,10 @@ impl<'a, Writer: Write> Printer<'a, Writer> { break None; } } + if is_empty { + self.print_header()?; is_empty = false; + } // squeeze is active, check if the line is the same // skip print if still squeezed, otherwise print and deactivate squeeze @@ -648,6 +653,8 @@ impl<'a, Writer: Write> Printer<'a, Writer> { // special ending if is_empty { + self.base_digits = 2; + self.print_header()?; if self.show_position_panel { write!(self.writer, "{0:9}", "│")?; } From 7de17c4f350f4269e055890803e6e6c45ea37c34 Mon Sep 17 00:00:00 2001 From: Sharif Haason Date: Sun, 27 Nov 2022 17:15:26 -0500 Subject: [PATCH 05/15] Adjust spaces on empty lines --- src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e7431e7..6cb102b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -339,7 +339,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> { fn panel_sz(&self) -> usize { // add one to include the trailing space of a group - let group_sz = 2 * self.group_bytes as usize + 1; + let group_sz = self.base_digits as usize * self.group_bytes as usize + 1; let group_per_panel = 8 / self.group_bytes as usize; // add one to include the leading space 1 + group_sz * group_per_panel @@ -514,7 +514,9 @@ impl<'a, Writer: Write> Printer<'a, Writer> { self.writer.write_all(b" ")?; } } - self.writer.write_all(b" ")?; + for _ in 0..self.base_digits { + self.writer.write_all(b" ")?; + } } Squeezer::Delete => self.writer.write_all(b" ")?, Squeezer::Ignore | Squeezer::Disabled => { From 7bb6343d2a0a8dfe720d51c5344d956606b85fda Mon Sep 17 00:00:00 2001 From: Sharif Haason Date: Sun, 27 Nov 2022 17:16:48 -0500 Subject: [PATCH 06/15] Add `--base`/`-b` argument --- src/bin/hexyl.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/bin/hexyl.rs b/src/bin/hexyl.rs index 4b4cf5b..a27e6e8 100644 --- a/src/bin/hexyl.rs +++ b/src/bin/hexyl.rs @@ -177,6 +177,17 @@ fn run() -> Result<(), AnyhowError> { The possible options are 1, 2, 4, 8. The default is 1", ), ) + .arg( + Arg::new("base") + .short('b') + .long("base") + .num_args(1) + .value_name("B") + .help( + "Sets the base used for the bytes. The possible options are \ + binary, octal, decimal, and hexadecimal." + ) + ) .arg( Arg::new("terminal_width") .long("terminal-width") From a8cffbb6df3e51337749a42a7231dd66b4c9ad55 Mon Sep 17 00:00:00 2001 From: Sharif Haason Date: Sun, 27 Nov 2022 17:17:25 -0500 Subject: [PATCH 07/15] Move `group_bytes` so it can be used for panels --- src/bin/hexyl.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/bin/hexyl.rs b/src/bin/hexyl.rs index a27e6e8..3a45603 100644 --- a/src/bin/hexyl.rs +++ b/src/bin/hexyl.rs @@ -331,6 +331,28 @@ fn run() -> Result<(), AnyhowError> { } }; + + let group_bytes = if let Some(group_bytes) = matches + .get_one::("group_bytes") + .map(|s| { + s.parse::().map(u8::from).context(anyhow!( + "failed to parse `--group-bytes`/`-g` arg {:?} as unsigned nonzero integer", + s + )) + }) + .transpose()? + { + if (group_bytes <= 8) && ((group_bytes & (group_bytes - 1)) == 0) { + group_bytes + } else { + return Err(anyhow!( + "Possible options for the `--group-bytes`/`-g` option are 1, 2, 4 or 8. " + )); + } + } else { + 1 + }; + let panels = if matches.get_one::("panels").map(String::as_ref) == Some("auto") { max_panels_fn(terminal_size().ok_or_else(|| anyhow!("not a TTY"))?.0 .0 as u64) } else if let Some(panels) = matches From 2861cd51ac2cf286a52b36f473e8e2fcb62ad898 Mon Sep 17 00:00:00 2001 From: Sharif Haason Date: Sun, 27 Nov 2022 17:17:52 -0500 Subject: [PATCH 08/15] Adjust panel calculation to account for base and group --- src/bin/hexyl.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/bin/hexyl.rs b/src/bin/hexyl.rs index 3a45603..da52f6e 100644 --- a/src/bin/hexyl.rs +++ b/src/bin/hexyl.rs @@ -321,9 +321,14 @@ fn run() -> Result<(), AnyhowError> { .transpose()? .unwrap_or(0); - let max_panels_fn = |terminal_width: u64| { + let max_panels_fn = |terminal_width: u64, base_digits: u64, group_bytes: u64| { let offset = if show_position_panel { 10 } else { 1 }; - let col_width = if show_char_panel { 35 } else { 26 }; + let col_width = if show_char_panel { + ((8 / group_bytes) * (base_digits * group_bytes + 1)) + 2 + 8 + } else { + ((8 / group_bytes) * (base_digits * group_bytes + 1)) + 2 + }; + dbg!(terminal_width, col_width); if (terminal_width - offset) / col_width < 1 { 1 } else { From e6000a56f4ad5cfa5104485a060402ce43c931ee Mon Sep 17 00:00:00 2001 From: Sharif Haason Date: Sun, 27 Nov 2022 17:18:38 -0500 Subject: [PATCH 09/15] Parse `-b` argument --- src/bin/hexyl.rs | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/bin/hexyl.rs b/src/bin/hexyl.rs index da52f6e..1b9dcf5 100644 --- a/src/bin/hexyl.rs +++ b/src/bin/hexyl.rs @@ -19,7 +19,7 @@ use thiserror::Error as ThisError; use terminal_size::terminal_size; -use hexyl::{BorderStyle, Input, PrinterBuilder}; +use hexyl::{Base, BorderStyle, Input, PrinterBuilder}; const DEFAULT_BLOCK_SIZE: i64 = 512; @@ -336,6 +336,37 @@ fn run() -> Result<(), AnyhowError> { } }; + let base = if let Some(base) = matches.get_one::("base") + .map(|s| { + if let Ok(base_num) = s.parse::() { + match base_num { + 2 => Ok(Base::Binary), + 8 => Ok(Base::Octal), + 10 => Ok(Base::Decimal), + 16 => Ok(Base::Hexadecimal), + _ => Err(anyhow!("The number provided is not a valid base. Valid bases are 2, 8, 10, and 16.")), + } + } else { + match s.as_str() { + "b" | "bin" | "binary" => Ok(Base::Binary), + "o" | "oct" | "octal" => Ok(Base::Octal), + "d" | "dec" | "decimal" => Ok(Base::Decimal), + "x" | "hex" | "hexadecimal" => Ok(Base::Hexadecimal), + _ => Err(anyhow!("The base provided is not valid. Valid bases are \"b\", \"o\", \"d\", and \"x\".")) + } + } + }).transpose()? { + base + } else { + Base::Hexadecimal + }; + + let base_digits = match base { + Base::Binary => 8, + Base::Octal => 3, + Base::Decimal => 3, + Base::Hexadecimal => 2, + }; let group_bytes = if let Some(group_bytes) = matches .get_one::("group_bytes") From fc794b290c5f00c86633da86d1a058982660b694 Mon Sep 17 00:00:00 2001 From: Sharif Haason Date: Sun, 27 Nov 2022 17:19:33 -0500 Subject: [PATCH 10/15] Account for new panel arguments --- src/bin/hexyl.rs | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/src/bin/hexyl.rs b/src/bin/hexyl.rs index 1b9dcf5..58cc698 100644 --- a/src/bin/hexyl.rs +++ b/src/bin/hexyl.rs @@ -390,7 +390,11 @@ fn run() -> Result<(), AnyhowError> { }; let panels = if matches.get_one::("panels").map(String::as_ref) == Some("auto") { - max_panels_fn(terminal_size().ok_or_else(|| anyhow!("not a TTY"))?.0 .0 as u64) + max_panels_fn( + terminal_size().ok_or_else(|| anyhow!("not a TTY"))?.0 .0 as u64, + base_digits, + group_bytes.into(), + ) } else if let Some(panels) = matches .get_one::("panels") .map(|s| { @@ -412,32 +416,11 @@ fn run() -> Result<(), AnyhowError> { }) .transpose()? { - max_panels_fn(terminal_width) + max_panels_fn(terminal_width, base_digits, group_bytes.into()) } else { 2 }; - let group_bytes = if let Some(group_bytes) = matches - .get_one::("group_bytes") - .map(|s| { - s.parse::().map(u8::from).context(anyhow!( - "failed to parse `--group-bytes`/`-g` arg {:?} as unsigned nonzero integer", - s - )) - }) - .transpose()? - { - if (group_bytes <= 8) && ((group_bytes & (group_bytes - 1)) == 0) { - group_bytes - } else { - return Err(anyhow!( - "Possible options for the `--group-bytes`/`-g` option are 1, 2, 4 or 8. " - )); - } - } else { - 1 - }; - let stdout = io::stdout(); let mut stdout_lock = BufWriter::new(stdout.lock()); @@ -449,6 +432,7 @@ fn run() -> Result<(), AnyhowError> { .enable_squeezing(squeeze) .num_panels(panels) .num_group_bytes(group_bytes) + .with_base(base) .build(); printer.display_offset(skip_offset + display_offset); printer.print_all(&mut reader).map_err(|e| anyhow!(e))?; From 5e3c49f933d834bd9874b6042ce5205145461af2 Mon Sep 17 00:00:00 2001 From: Sharif Haason Date: Sun, 27 Nov 2022 17:19:48 -0500 Subject: [PATCH 11/15] `cargo fmt` --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6cb102b..42878d2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -581,7 +581,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> { // if less are read, that indicates end of file after if is_empty { self.print_header()?; - is_empty = false; + is_empty = false; } // perform second check on read @@ -601,7 +601,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> { } if is_empty { self.print_header()?; - is_empty = false; + is_empty = false; } // squeeze is active, check if the line is the same From 2a4b17a162ab83e74f65bd5517bdcea76f2116b4 Mon Sep 17 00:00:00 2001 From: Sharif Haason Date: Sun, 27 Nov 2022 17:32:18 -0500 Subject: [PATCH 12/15] Add tests for alternate base --- tests/integration_tests.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index e7a5716..afd66c7 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -551,3 +551,21 @@ mod group { ); } } + +mod base { + use super::hexyl; + use super::PrettyAssert; + + #[test] + fn base2() { + hexyl() + .arg("ascii") + .arg("--plain") + .arg("--base=binary") + .assert() + .success() + .pretty_stdout( + " 00110000 00110001 00110010 00110011 00110100 00110101 00110110 00110111 00111000 00111001 01100001 01100010 01100011 01100100 01100101 00001010 \n" + ); + } +} \ No newline at end of file From 32f4ce9987beac7ae27cba1337e5065c149de5ff Mon Sep 17 00:00:00 2001 From: Sharif Haason Date: Sun, 27 Nov 2022 17:52:29 -0500 Subject: [PATCH 13/15] `cargo fmt` --- tests/integration_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index afd66c7..7a0fae1 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -568,4 +568,4 @@ mod base { " 00110000 00110001 00110010 00110011 00110100 00110101 00110110 00110111 00111000 00111001 01100001 01100010 01100011 01100100 01100101 00001010 \n" ); } -} \ No newline at end of file +} From 7847e8cd33662246daf2ff1707001421c102b622 Mon Sep 17 00:00:00 2001 From: Sharif Haason Date: Sun, 27 Nov 2022 19:45:33 -0500 Subject: [PATCH 14/15] Remove debug statement --- src/bin/hexyl.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bin/hexyl.rs b/src/bin/hexyl.rs index 58cc698..176c8f2 100644 --- a/src/bin/hexyl.rs +++ b/src/bin/hexyl.rs @@ -328,7 +328,6 @@ fn run() -> Result<(), AnyhowError> { } else { ((8 / group_bytes) * (base_digits * group_bytes + 1)) + 2 }; - dbg!(terminal_width, col_width); if (terminal_width - offset) / col_width < 1 { 1 } else { From 030235afb7cf6591bc5af021fde05f5c41190fb2 Mon Sep 17 00:00:00 2001 From: Sharif Haason Date: Sun, 4 Dec 2022 21:36:42 -0500 Subject: [PATCH 15/15] Improve help text for `--base` --- src/bin/hexyl.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bin/hexyl.rs b/src/bin/hexyl.rs index 176c8f2..58e53ac 100644 --- a/src/bin/hexyl.rs +++ b/src/bin/hexyl.rs @@ -185,7 +185,8 @@ fn run() -> Result<(), AnyhowError> { .value_name("B") .help( "Sets the base used for the bytes. The possible options are \ - binary, octal, decimal, and hexadecimal." + binary, octal, decimal, and hexadecimal. The default base \ + is hexadecimal." ) ) .arg(