diff --git a/Cargo.lock b/Cargo.lock index 24fc712..3291450 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -128,6 +128,7 @@ dependencies = [ "assert_cmd", "chrono", "diff", + "itoa", "predicates", "pretty_assertions", "regex", @@ -190,6 +191,12 @@ dependencies = [ "cc", ] +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "js-sys" version = "0.3.69" diff --git a/Cargo.toml b/Cargo.toml index 477467c..6fa1a3c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ path = "src/main.rs" [dependencies] chrono = "0.4.38" diff = "0.1.13" +itoa = "1.0.11" regex = "1.10.4" same-file = "1.0.6" unicode-width = "0.2.0" diff --git a/src/cmp.rs b/src/cmp.rs index 29b8775..a337c12 100644 --- a/src/cmp.rs +++ b/src/cmp.rs @@ -483,6 +483,24 @@ fn is_ascii_printable(byte: u8) -> bool { c.is_ascii() && !c.is_ascii_control() } +#[inline] +fn format_octal(byte: u8, buf: &mut [u8; 3]) -> &str { + *buf = [b' ', b' ', b'0']; + + let mut num = byte; + let mut idx = 2; // Start at the last position in the buffer + + // Generate octal digits + while num > 0 { + buf[idx] = b'0' + num % 8; + num /= 8; + idx = idx.saturating_sub(1); + } + + // SAFETY: the operations we do above always land within ascii range. + unsafe { std::str::from_utf8_unchecked(&buf[..]) } +} + #[inline] fn format_byte(byte: u8) -> String { let mut byte = byte; @@ -520,15 +538,20 @@ fn report_verbose_diffs(diffs: Vec<(usize, u8, u8)>, params: &Params) -> Result< // Obtain the width of the first column from the last byte offset. let width = format!("{}", offset).len(); + let mut at_byte_buf = itoa::Buffer::new(); + let mut from_oct = [0u8; 3]; // for octal conversions + let mut to_oct = [0u8; 3]; + if params.print_bytes { for (at_byte, from_byte, to_byte) in diffs { + let at_byte_str = at_byte_buf.format(at_byte); writeln!( stdout, - "{:>width$} {:>3o} {:4} {:>3o} {}", - at_byte, - from_byte, + "{:>width$} {} {:4} {} {}", + at_byte_str, + format_octal(from_byte, &mut from_oct), format_byte(from_byte), - to_byte, + format_octal(to_byte, &mut to_oct), format_byte(to_byte), ) .map_err(|e| { @@ -540,12 +563,13 @@ fn report_verbose_diffs(diffs: Vec<(usize, u8, u8)>, params: &Params) -> Result< } } else { for (at_byte, from_byte, to_byte) in diffs { + let at_byte_str = at_byte_buf.format(at_byte); writeln!( stdout, - "{:>width$} {:>3o} {:>3o}", - at_byte, - from_byte, - to_byte, + "{:>width$} {} {}", + at_byte_str, + format_octal(from_byte, &mut from_oct), + format_octal(to_byte, &mut to_oct), width = width ) .map_err(|e| {