120 Commits
Author SHA1 Message Date
David Peter 421bd73ec1 Revert "Replace libc with rustix"
This reverts commit 571312dd6e.
2022-12-05 09:52:27 +01:00
David Peter e888021a48 Update version in README, man page 2022-12-05 09:48:10 +01:00
David Peter 7d38f70918 Show 0x00-bytes as '⋄' instead of '0', closes #166 2022-12-05 09:45:38 +01:00
David Peter c6af2edda8 Bump version 2022-12-05 09:32:07 +01:00
David Peter a7fadfaaf2 Update dependencies 2022-12-05 09:31:43 +01:00
David Peter 8577a17b14 Ignore EPIPE silently
fixes a regression introduced in a6aeabfde4

closes #181
2022-12-05 09:30:13 +01:00
David Peter 2d8b600c48 Update CHANGELOG 2022-12-05 09:11:47 +01:00
David Peter f8601e5bc9 Merge pull request #180 from sharifhsn/altdeps
Replace outdated dependencies
2022-12-05 09:03:40 +01:00
David Peter 9770b89cf4 Merge pull request #178 from sharifhsn/base
[feature] Implement alternate bases
2022-12-05 09:03:03 +01:00
Sharif Haason 571312dd6e Replace libc with rustix 2022-12-04 21:48:10 -05:00
Sharif Haason fcd09fffac Relax anstyle version 2022-12-04 21:43:03 -05:00
Sharif Haason 188e753675 Replace atty with is-terminal 2022-12-04 21:42:44 -05:00
Sharif Haason 030235afb7 Improve help text for --base 2022-12-04 21:36:42 -05:00
Sharif Haason 7847e8cd33 Remove debug statement 2022-11-27 19:45:33 -05:00
Sharif Haason 32f4ce9987 cargo fmt 2022-11-27 17:52:29 -05:00
Sharif Haason 2a4b17a162 Add tests for alternate base 2022-11-27 17:32:18 -05:00
Sharif Haason 5e3c49f933 cargo fmt 2022-11-27 17:19:48 -05:00
Sharif Haason fc794b290c Account for new panel arguments 2022-11-27 17:19:33 -05:00
Sharif Haason e6000a56f4 Parse -b argument 2022-11-27 17:18:38 -05:00
Sharif Haason 2861cd51ac Adjust panel calculation to account for base and group 2022-11-27 17:17:52 -05:00
Sharif Haason a8cffbb6df Move group_bytes so it can be used for panels 2022-11-27 17:17:25 -05:00
Sharif Haason 7bb6343d2a Add --base/-b argument 2022-11-27 17:16:48 -05:00
Sharif Haason 7de17c4f35 Adjust spaces on empty lines 2022-11-27 17:15:26 -05:00
Sharif Haason ec61c2a789 Print header only if non-empty 2022-11-27 17:14:30 -05:00
Sharif Haason 7f7b88a914 Adjust tests 2022-11-27 17:13:36 -05:00
Sharif Haason 85fa75ba67 Differentiate format on base 2022-11-27 17:11:55 -05:00
Sharif Haason d5d645fc48 Add Base to Printer 2022-11-27 17:11:21 -05:00
David Peter 8d3aa65134 Merge pull request #176 from sharifhsn/anstyle
Change `ansi_term` to `anstyle`
2022-11-27 21:02:26 +01:00
Sharif Haason 252b4e84c3 Merge branch 'master' into anstyle 2022-11-27 10:03:53 -05:00
Sharif Haason 3dc118d0ad cargo update 2022-11-27 09:47:38 -05:00
Mikhail Katychev b1ff8b6ce4 added squeeze tests 2022-11-26 20:18:21 +01:00
David Peter fe65792b96 Add CHANGELOG entry 2022-11-26 13:07:06 +01:00
David Peter 31c0bcfeae Improve error messages 2022-11-26 13:07:06 +01:00
RinHizakura c0f94ad6aa Refine the support of byte grouping 2022-11-26 13:07:06 +01:00
RinHizakura 55fed5e3c0 Fix for clap4 2022-11-26 13:07:06 +01:00
RinHizakura aeee0a1033 Add new integration tests for group bytes feature 2022-11-26 13:07:06 +01:00
RinHizakura 179c8f40a2 Support byte grouping 2022-11-26 13:07:06 +01:00
Sharif Haason fb2500d7d6 Include Cargo.lock 2022-11-19 11:40:03 -05:00
Sharif Haason ad9ecda952 Remove once_cell dependency 2022-11-19 11:04:59 -05:00
Sharif Haason c43effefd6 cargo fmt 2022-11-19 11:04:13 -05:00
Sharif Haason 0b6454ed9d Use Vec of enums for color instead of HashMap 2022-11-19 10:50:31 -05:00
Sharif Haason 557ae66ed5 Update Cargo.lock 2022-11-18 16:15:49 -05:00
Sharif Haason df1afdc73f Merge branch 'anstyle' of https://github.com/sharifhsn/hexyl into anstyle 2022-11-18 16:15:12 -05:00
Sharif Haason 9106b899b2 Bump MSRV 2022-11-18 19:22:24 +01:00
Sharif Haason df1c36e5a7 Satisfy clippy 2022-11-18 19:22:24 +01:00
Sharif Haason ac610f7bad Add get_one and fix ordering 2022-11-18 19:22:24 +01:00
Sharif Haason 767740865f Update predicate for default_value_if 2022-11-18 19:22:24 +01:00
Sharif Haason 1fb324f411 Use ArgAction for flags 2022-11-18 19:22:24 +01:00
Sharif Haason 3d0bc3d0eb Replace 'value_of with get_one::<String>` 2022-11-18 19:22:24 +01:00
Sharif Haason 8a52261a50 Replace possible_values with value_parser 2022-11-18 19:22:24 +01:00
Sharif Haason ccc4fb9ba9 Replace takes_value with num_args 2022-11-18 19:22:24 +01:00
Sharif Haason 0baa22f152 DeriveDisplayOrder now default 2022-11-18 19:22:24 +01:00
Sharif Haason 165ced9307 Update to clap 4.0 2022-11-18 19:22:24 +01:00
Sharif Haason 3888a20dfe Bump MSRV 2022-11-18 11:06:18 -05:00
Sharif Haason 75b37fa125 Use compatible lockfile 2022-11-18 11:01:39 -05:00
Sharif Haason 794e1935e3 Prerender color strings for better performance 2022-11-18 10:39:54 -05:00
Sharif Haason c49aa079b4 Add color only when needed 2022-11-18 08:19:13 -05:00
Sharif Haason 675ef6d4a8 Remove calls to ansi_term 2022-11-17 22:33:49 -05:00
Sharif Haason eade38c94a Explicitly paint with style formatting 2022-11-17 22:33:03 -05:00
Sharif Haason 98ceec18cd Replace colors with ANSI styles 2022-11-17 22:15:53 -05:00
Sharif Haason a49f295acc Replace deprecated ansi_term with anstyle 2022-11-17 22:12:00 -05:00
Sharif Haason 0caab15255 Document the main loop 2022-11-13 22:15:41 +01:00
Sharif Haason 828fb210ce Use repeat byte when discovering squeeze 2022-11-13 22:15:41 +01:00
Sharif Haason 1e43783616 Clean up flags for ergonomics 2022-11-13 22:15:41 +01:00
Sharif Haason 6b7cfefec6 Use repeated byte optimization on nonzero bytes 2022-11-13 22:15:41 +01:00
Sharif Haason 5f82942f98 Add second check if read fails unexpectedly 2022-11-13 22:15:41 +01:00
Sharif Haason f6a1c4e8e3 Add unit tests for new implementation of squeeze 2022-11-13 22:15:41 +01:00
Sharif Haason b4fb1b079c Print last line only when squeezed 2022-11-13 22:15:41 +01:00
Sharif Haason f9f59d653d Print asterisk when no position panel 2022-11-13 22:15:41 +01:00
Sharif Haason c82695f0a9 Fix incomplete line ending when squeezed 2022-11-13 22:15:41 +01:00
Sharif Haason 9d938b11ed Remove unnecessary ending case (covered by next) 2022-11-13 22:15:41 +01:00
Sharif Haason d5982c0eb0 Optimize line check when squeezing zero bytes 2022-11-13 22:15:41 +01:00
Sharif Haason 1502419ad4 Document byte_hex_panel_g 2022-11-13 22:15:41 +01:00
Sharif Haason f5be845d70 Satisfy clippy 2022-11-13 22:15:41 +01:00
Sharif Haason 664025477b Alter when position panel is called 2022-11-13 22:15:41 +01:00
Sharif Haason 074bc791c2 Fix incomplete line ending 2022-11-13 22:15:41 +01:00
Sharif Haason 77a4ad25f1 Remove unnecessary import 2022-11-13 22:15:41 +01:00
Sharif Haason ca31d466ba Keep newline consistent 2022-11-13 22:15:41 +01:00
Sharif Haason 945e7a3472 Remove unnecessary squeezer module 2022-11-13 22:15:41 +01:00
Sharif Haason 75d612ff11 Alter newline usage 2022-11-13 22:15:41 +01:00
Sharif Haason 15e8abfc9a Complete architectural rewrite (intentionally fails) 2022-11-13 22:15:41 +01:00
Sharif Haason b36d74ed9d Track squeeze_byte correctly 2022-11-13 22:15:41 +01:00
Sharif Haason 094bf63f02 Eliminate unnecessary call to active 2022-11-13 22:15:41 +01:00
Sharif Haason e0e870de27 Store squeezed byte instead of pushing to vector 2022-11-13 22:15:41 +01:00
Sharif Haason 966421c522 Undo inlining to satisfy MSRV 2022-11-13 22:15:41 +01:00
Sharif Haason 166c2cc46b Inline StdoutLock variable 2022-11-13 22:15:41 +01:00
Sharif Haason 74a5e4bc84 Print first line always 2022-11-13 22:15:41 +01:00
Sharif Haason 363ea0a586 Undo perf regression on squeezer 2022-11-13 22:15:41 +01:00
Sharif Haason 1c4c7ed9a5 Satisfy clippy 2022-11-13 22:15:41 +01:00
Sharif Haason b5c224c119 Fix for no position panel 2022-11-13 22:15:41 +01:00
Sharif Haason d6e34d9dd2 Fix issues with hello_world_elf64 2022-11-13 22:15:41 +01:00
Sharif Haason 1cb346bd13 Fixes --no-characters causes output artifacts when squeezing lines #171 2022-11-13 22:15:41 +01:00
Sharif Haason daa40900bd Fix char panel showing even if disabled 2022-11-13 22:15:41 +01:00
Sharif Haason d98c6edb55 Fix overflow when printing without char panel 2022-11-13 22:15:41 +01:00
Sharif Haason 73bfc68cd0 cargo fmt 2022-11-13 22:15:41 +01:00
Sharif Haason 5d3f36d066 Remove write! formatting from hot loop 2022-11-13 22:15:41 +01:00
Sharif Haason d214bc63f1 Precalculate position formatting in Printer state 2022-11-13 22:15:41 +01:00
Sharif Haason a6aeabfde4 Refactor code to replace manual buffering with BufReader and BufWriter 2022-11-13 22:15:41 +01:00
Sharif Haason 9602667991 Rename with_panels to num_panels 2022-10-04 18:09:47 +02:00
Sharif Haason 9ccf18f4c0 Update CHANGELOG.md with PrinterBuilder 2022-10-04 18:09:47 +02:00
Sharif Haason aa921ca184 Rename with_squeeze to enable_squeezing 2022-10-04 18:09:47 +02:00
Sharif Haason 4823523b7d Remove superfluous with_writer function 2022-10-04 18:09:47 +02:00
Sharif Haason 4569c8f871 Self-document simple.rs example with builder API 2022-10-04 18:09:47 +02:00
Sharif Haason 80163764c3 Implement builder pattern 2022-10-04 18:09:47 +02:00
Sharif Haason 9bc81820e7 Update CHANGELOG 2022-09-11 21:45:06 +02:00
Sharif Haason 273ef0c045 Remove short options for panels and terminal-width 2022-09-11 21:45:06 +02:00
Sharif Haason ac1a67e90c Fix abbreviation clash 2022-09-11 21:45:06 +02:00
Sharif Haason 12324d615a Rename --columns to --panels 2022-09-11 21:45:06 +02:00
Sharif Haason 6b062ba127 Fix typo 2022-09-11 21:45:06 +02:00
Sharif Haason 8c7c3a073c Use --columns=auto instead of --auto-width 2022-09-11 21:45:06 +02:00
Sharif Haason 0565901fad Return a proper error if terminal size fails 2022-09-11 21:45:06 +02:00
Sharif Haason 41b3241718 Change columns type to u16 2022-09-11 21:45:06 +02:00
Sharif Haason 975a406d20 Remove debugging line 2022-09-11 21:45:06 +02:00
Sharif Haason aa43c20f39 Bump MSRV 2022-09-11 21:45:06 +02:00
Sharif Haason 1fdd770093 Implement -a and -t for terminal width setting 2022-09-11 21:45:06 +02:00
Sharif Haason a3fde45c18 Added test for multiple columns 2022-09-11 21:45:06 +02:00
Sharif Haason 85659a9cd6 Prevent overflow when columns >= 32 2022-09-11 21:45:06 +02:00
sharifandDavid Peter 2a4a22c9cb Update src/squeezer.rs
Co-authored-by: David Peter <sharkdp@users.noreply.github.com>
2022-09-11 21:45:06 +02:00
Sharif Haason b820bdfeca cargo fmt 2022-09-11 21:45:06 +02:00
Sharif Haason b9348ffb1d Adds --columns for Print using custom width #13 2022-09-11 21:45:06 +02:00
11 changed files with 1233 additions and 993 deletions

No files matched your search

+1 -1
View File
@@ -1,7 +1,7 @@
name: CICD
env:
MIN_SUPPORTED_RUST_VERSION: "1.56.1"
MIN_SUPPORTED_RUST_VERSION: "1.60.0"
CICD_INTERMEDIATES_DIR: "_cicd-intermediates"
on:
+13 -5
View File
@@ -1,19 +1,27 @@
# unreleased
## Changes
## Features
- Significantly improved performance, see #173 and #176 (@sharifhsn)
- Added variable panels through the `--panels` and `--terminal-width` flags, see [#13](https://github.com/sharkdp/hexyl/issues/13) and [#164](https://github.com/sharkdp/hexyl/pull/164) (@sharifhsn)
- Added new `--group-bytes`/`-g` option, see #104 and #170 (@RinHizakura)
- Added new `--base B` option (where `B` can be `binary`, `octal`, `decimal` or `hexadecimal`), see #147 and #178 (@sharifhsn)
- Show actual zero bytes as `⋄` in the character panel (previously: `0`), in order not to confuse them with ASCII
`0` bytes if colors are deactivated. Closes #166 (@sharkdp)
## Bugfixes
## `hexyl` as a library
- Breaking change: `Printer::new` is deprecated as a part of the public API. Alternatively, you can now construct a `Printer` using the `PrinterBuilder` builder API, see [#168](https://github.com/sharkdp/hexyl/pull/168). (@sharifhsn)
## Other
- More tests for the squeezing feature, see #177 (@mkatychev)
## Packaging
## Thank you
Special thanks go to @sharifhsn, not just for the new features,
bugfixes and performance improvements. But also for many internal
improvements of the code base and other maintenance tasks.
# v0.10.0
Generated
+174 -162
View File
@@ -1,63 +1,42 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.18"
version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [
"memchr",
]
[[package]]
name = "ansi_term"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
]
[[package]]
name = "anstyle"
version = "1.0.13"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
checksum = "58bb0ec944fe041c41e32dcd60b49327fcb7ff761433838878cc97ddecf16db7"
[[package]]
name = "anyhow"
version = "1.0.57"
version = "1.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc"
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
[[package]]
name = "assert_cmd"
version = "2.1.2"
version = "2.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c5bcfa8749ac45dd12cb11055aeeb6b27a3895560d60d71e3c23bf979e60514"
checksum = "fa3d466004a8b4cb1bc34044240a2fd29d17607e2e3bd613eb44fd48e8100da3"
dependencies = [
"anstyle",
"bstr",
"libc",
"predicates 3.1.4",
"doc-comment",
"predicates",
"predicates-core",
"predicates-tree",
"wait-timeout",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.1.0"
@@ -72,67 +51,82 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bstr"
version = "1.12.1"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
checksum = "fca0852af221f458706eb0725c03e4ed6c46af9ac98e6a689d5e634215d594dd"
dependencies = [
"memchr",
"once_cell",
"regex-automata",
"serde",
]
[[package]]
name = "cc"
version = "1.0.73"
version = "1.0.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
[[package]]
name = "clap"
version = "3.2.11"
version = "4.0.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d646c7ade5eb07c4aa20e907a922750df0c448892513714fd3e4acbc7130829f"
checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d"
dependencies = [
"atty",
"bitflags",
"clap_lex",
"indexmap",
"is-terminal",
"once_cell",
"strsim",
"termcolor",
"terminal_size 0.1.17",
"textwrap",
"terminal_size",
]
[[package]]
name = "clap_lex"
version = "0.2.4"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "const_format"
version = "0.2.23"
version = "0.2.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0936ffe6d0c8d6a51b3b0a73b2acbe925d786f346cf45bfddc8341d79fb7dc8a"
checksum = "7309d9b4d3d2c0641e018d449232f2e28f1b22933c137f157d3dbc14228b8c0e"
dependencies = [
"const_format_proc_macros",
]
[[package]]
name = "const_format_proc_macros"
version = "0.2.22"
version = "0.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef196d5d972878a48da7decb7686eded338b4858fbabeed513d63a7c98b2b82d"
checksum = "d897f47bf7270cf70d370f8f98c1abb6d2d4cf60a6845d30e05bfb90c6568650"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "ctor"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "diff"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]]
name = "difflib"
version = "0.4.0"
@@ -140,10 +134,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
[[package]]
name = "either"
version = "1.6.1"
name = "doc-comment"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]]
name = "either"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "errno"
@@ -175,79 +175,80 @@ dependencies = [
"num-traits",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "hermit-abi"
version = "0.1.19"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
dependencies = [
"libc",
]
[[package]]
name = "hexyl"
version = "0.10.0"
version = "0.11.0"
dependencies = [
"ansi_term",
"anstyle",
"anyhow",
"assert_cmd",
"atty",
"clap",
"const_format",
"is-terminal",
"libc",
"predicates 2.1.1",
"terminal_size 0.2.1",
"predicates",
"pretty_assertions",
"terminal_size",
"thiserror",
]
[[package]]
name = "indexmap"
version = "1.8.1"
name = "io-lifetimes"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
dependencies = [
"autocfg",
"hashbrown",
"libc",
"windows-sys",
]
[[package]]
name = "io-lifetimes"
version = "0.7.2"
name = "is-terminal"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24c3f4eff5495aee4c0399d7b6a0dc2b6e81be84242ffbfcf253ebacccc1d0cb"
checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330"
dependencies = [
"hermit-abi",
"io-lifetimes",
"rustix",
"windows-sys",
]
[[package]]
name = "itertools"
version = "0.10.3"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "libc"
version = "0.2.182"
version = "0.2.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
[[package]]
name = "linux-raw-sys"
version = "0.0.46"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d"
checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f"
[[package]]
name = "memchr"
version = "2.8.0"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "normalize-line-endings"
@@ -266,21 +267,30 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.13.0"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "os_str_bytes"
version = "6.0.1"
version = "6.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "029d8d0b2f198229de29dca79676f2738ff952edf3fde542eb8bf94d8c21b435"
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
[[package]]
name = "output_vt100"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
dependencies = [
"winapi",
]
[[package]]
name = "predicates"
version = "2.1.1"
version = "2.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5aab5be6e4732b473071984b3164dbbfb7a3674d30ea5ff44410b6bcd960c3c"
checksum = "f54fc5dc63ed3bbf19494623db4f3af16842c0d975818e469022d09e53f0aa05"
dependencies = [
"difflib",
"float-cmp",
@@ -290,56 +300,57 @@ dependencies = [
"regex",
]
[[package]]
name = "predicates"
version = "3.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ada8f2932f28a27ee7b70dd6c1c39ea0675c55a36879ab92f3a715eaa1e63cfe"
dependencies = [
"anstyle",
"difflib",
"predicates-core",
]
[[package]]
name = "predicates-core"
version = "1.0.10"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cad38746f3166b4031b1a0d39ad9f954dd291e7854fcc0eed52ee41a0b50d144"
checksum = "72f883590242d3c6fc5bf50299011695fa6590c2c70eac95ee1bdb9a733ad1a2"
[[package]]
name = "predicates-tree"
version = "1.0.5"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d86de6de25020a36c6d3643a86d9a6a9f552107c0559c60ea03551b5e16c032"
checksum = "54ff541861505aabf6ea722d2131ee980b8276e10a1297b94e896dd8b621850d"
dependencies = [
"predicates-core",
"termtree",
]
[[package]]
name = "proc-macro2"
version = "1.0.39"
name = "pretty_assertions"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f"
checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755"
dependencies = [
"ctor",
"diff",
"output_vt100",
"yansi",
]
[[package]]
name = "proc-macro2"
version = "1.0.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.18"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.5.6"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a"
dependencies = [
"aho-corasick",
"memchr",
@@ -348,21 +359,21 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.4.14"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
[[package]]
name = "regex-syntax"
version = "0.6.26"
version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "rustix"
version = "0.35.7"
version = "0.36.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d51cc38aa10f6bbb377ed28197aa052aa4e2b762c22be9d3153d01822587e787"
checksum = "cb93e85278e08bb5788653183213d3a60fc242b10cb9be96586f5a73dcb67c23"
dependencies = [
"bitflags",
"errno",
@@ -374,9 +385,9 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.185"
version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be9b6f69f1dfd54c3b568ffa45c310d6973a5e5148fd40cf515acaf38cf5bc31"
checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055"
[[package]]
name = "strsim"
@@ -386,9 +397,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.95"
version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942"
checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
dependencies = [
"proc-macro2",
"quote",
@@ -406,19 +417,9 @@ dependencies = [
[[package]]
name = "terminal_size"
version = "0.1.17"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "terminal_size"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8440c860cf79def6164e4a0a983bcc2305d82419177a0e0c71930d049e3ac5a1"
checksum = "cb20089a8ba2b69debd491f8d2d023761cbf196e999218c591fa1e7e15a21907"
dependencies = [
"rustix",
"windows-sys",
@@ -426,33 +427,24 @@ dependencies = [
[[package]]
name = "termtree"
version = "0.2.4"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b"
[[package]]
name = "textwrap"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
dependencies = [
"terminal_size 0.1.17",
]
checksum = "95059e91184749cb66be6dc994f67f182b6d897cb3df74a5bf66b5e709295fd8"
[[package]]
name = "thiserror"
version = "1.0.31"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.31"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
dependencies = [
"proc-macro2",
"quote",
@@ -461,15 +453,15 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.0"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
[[package]]
name = "unicode-xid"
version = "0.2.3"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "wait-timeout"
@@ -513,43 +505,63 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.36.1"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_msvc"
version = "0.36.1"
name = "windows_aarch64_gnullvm"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
[[package]]
name = "windows_i686_gnu"
version = "0.36.1"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
[[package]]
name = "windows_i686_msvc"
version = "0.36.1"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
[[package]]
name = "windows_x86_64_gnu"
version = "0.36.1"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
[[package]]
name = "windows_x86_64_msvc"
version = "0.36.1"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
[[package]]
name = "yansi"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
+7 -6
View File
@@ -7,26 +7,27 @@ license = "MIT/Apache-2.0"
name = "hexyl"
readme = "README.md"
repository = "https://github.com/sharkdp/hexyl"
version = "0.10.0"
version = "0.11.0"
edition = "2021"
[dependencies]
ansi_term = "0.12"
anstyle = "0.2"
anyhow = "1.0"
atty = "0.2"
const_format = "0.2"
is-terminal = "0.4"
libc = "0.2"
thiserror = "1.0"
terminal_size = "0.2"
[dependencies.clap]
version = "3"
version = "4"
default-features = false
features = ["std", "suggestions", "color", "wrap_help", "cargo"]
features = ["std", "suggestions", "color", "wrap_help", "cargo", "help", "usage", "error-context"]
[dev-dependencies]
assert_cmd = "2.1"
assert_cmd = "2.0"
predicates = "2.0"
pretty_assertions = "1.3.0"
[profile.release]
lto = true
+1 -1
View File
@@ -31,7 +31,7 @@ If you use an older version of Ubuntu, you can download
the latest `.deb` package from the release page and install it via:
``` bash
sudo dpkg -i hexyl_0.10.0_amd64.deb # adapt version number and architecture
sudo dpkg -i hexyl_0.11.0_amd64.deb # adapt version number and architecture
```
### On Debian
+2 -2
View File
@@ -1,6 +1,6 @@
% HEXYL(1) hexyl 0.10.0 | General Commands Manual
% HEXYL(1) hexyl 0.11.0 | General Commands Manual
%
% 2022-03-23
% 2022-12-05
<!--
This man page is written in Pandoc's Markdown.
+10 -17
View File
@@ -1,6 +1,6 @@
use std::io;
use hexyl::{BorderStyle, Printer};
use hexyl::{BorderStyle, PrinterBuilder};
fn main() {
let input = vec![
@@ -11,21 +11,14 @@ fn main() {
let stdout = io::stdout();
let mut handle = stdout.lock();
let show_color = true;
let show_char_panel = true;
let show_position_panel = true;
let use_squeezing = false;
let border_style = BorderStyle::Unicode;
let columns = 2;
let mut printer = Printer::new(
&mut handle,
show_color,
show_char_panel,
show_position_panel,
border_style,
use_squeezing,
columns,
);
let mut printer = PrinterBuilder::new(&mut handle)
.show_color(true)
.show_char_panel(true)
.show_position_panel(true)
.with_border_style(BorderStyle::Unicode)
.enable_squeezing(false)
.num_panels(2)
.num_group_bytes(1)
.build();
printer.print_all(&input[..]).unwrap();
}
+180 -104
View File
@@ -3,14 +3,15 @@ extern crate clap;
use std::convert::TryFrom;
use std::fs::File;
use std::io::{self, prelude::*, SeekFrom};
use std::num::{NonZeroI64, NonZeroU16};
use std::io::{self, prelude::*, BufWriter, SeekFrom};
use std::num::{NonZeroI64, NonZeroU64, NonZeroU8};
use clap::{crate_name, crate_version, AppSettings, Arg, ColorChoice, Command};
use clap::builder::ArgPredicate;
use clap::{crate_name, crate_version, Arg, ArgAction, ColorChoice, Command};
use atty::Stream;
use is_terminal::IsTerminal;
use anyhow::{anyhow, Context, Error as AnyhowError};
use anyhow::{anyhow, Context, Result};
use const_format::formatcp;
@@ -18,13 +19,12 @@ use thiserror::Error as ThisError;
use terminal_size::terminal_size;
use hexyl::{BorderStyle, Input, Printer};
use hexyl::{Base, BorderStyle, Input, PrinterBuilder};
const DEFAULT_BLOCK_SIZE: i64 = 512;
fn run() -> Result<(), AnyhowError> {
fn run() -> Result<()> {
let command = Command::new(crate_name!())
.setting(AppSettings::DeriveDisplayOrder)
.color(ColorChoice::Auto)
.max_term_width(90)
.version(crate_version!())
@@ -37,7 +37,7 @@ fn run() -> Result<(), AnyhowError> {
Arg::new("length")
.short('n')
.long("length")
.takes_value(true)
.num_args(1)
.value_name("N")
.help(
"Only read N bytes from the input. The N argument can also include a \
@@ -51,7 +51,7 @@ fn run() -> Result<(), AnyhowError> {
Arg::new("bytes")
.short('c')
.long("bytes")
.takes_value(true)
.num_args(1)
.value_name("N")
.conflicts_with("length")
.help("An alias for -n/--length"),
@@ -59,9 +59,9 @@ fn run() -> Result<(), AnyhowError> {
.arg(
Arg::new("count")
.short('l')
.takes_value(true)
.num_args(1)
.value_name("N")
.conflicts_with_all(&["length", "bytes"])
.conflicts_with_all(["length", "bytes"])
.hide(true)
.help("Yet another alias for -n/--length"),
)
@@ -69,7 +69,7 @@ fn run() -> Result<(), AnyhowError> {
Arg::new("skip")
.short('s')
.long("skip")
.takes_value(true)
.num_args(1)
.value_name("N")
.help(
"Skip the first N bytes of the input. The N argument can also include \
@@ -80,7 +80,7 @@ fn run() -> Result<(), AnyhowError> {
.arg(
Arg::new("block_size")
.long("block-size")
.takes_value(true)
.num_args(1)
.value_name("SIZE")
.help(formatcp!(
"Sets the size of the `block` unit to SIZE (default is {}).\n\
@@ -92,6 +92,7 @@ fn run() -> Result<(), AnyhowError> {
Arg::new("nosqueezing")
.short('v')
.long("no-squeezing")
.action(ArgAction::SetFalse)
.help(
"Displays all input data. Otherwise any number of groups of output \
lines which would be identical to the preceding group of lines, are \
@@ -101,49 +102,51 @@ fn run() -> Result<(), AnyhowError> {
.arg(
Arg::new("color")
.long("color")
.takes_value(true)
.num_args(1)
.value_name("WHEN")
.possible_values(&["always", "auto", "never"])
.default_value_if("plain", None, Some("never"))
.value_parser(["always", "auto", "never"])
.default_value_if("plain", ArgPredicate::IsPresent, Some("never"))
.default_value("always")
.help(
"When to use colors. The auto-mode only displays colors if the output \
goes to an interactive terminal",
),
)
.arg(Arg::new("plain").short('p').long("plain").help(
"Display output with --no-characters, --no-position, --border=none, and --color=never.",
))
.arg(
Arg::new("border")
.long("border")
.takes_value(true)
.num_args(1)
.value_name("STYLE")
.possible_values(&["unicode", "ascii", "none"])
.default_value_if("plain", None, Some("none"))
.value_parser(["unicode", "ascii", "none"])
.default_value_if("plain", ArgPredicate::IsPresent, Some("none"))
.default_value("unicode")
.help(
"Whether to draw a border with Unicode characters, ASCII characters, \
or none at all",
),
)
.arg(Arg::new("plain").short('p').long("plain").action(ArgAction::SetTrue).help(
"Display output with --no-characters, --no-position, --border=none, and --color=never.",
))
.arg(
Arg::new("no_chars")
.short('C')
.long("no-characters")
.action(ArgAction::SetFalse)
.help("Whether to display the character panel on the right."),
)
.arg(
Arg::new("no_position")
.short('P')
.long("no-position")
.action(ArgAction::SetFalse)
.help("Whether to display the position panel on the left."),
)
.arg(
Arg::new("display_offset")
.short('o')
.long("display-offset")
.takes_value(true)
.num_args(1)
.value_name("N")
.help(
"Add N bytes to the displayed file position. The N argument can also \
@@ -153,53 +156,65 @@ fn run() -> Result<(), AnyhowError> {
),
)
.arg(
Arg::new("columns")
.short('w')
.long("columns")
.takes_value(true)
Arg::new("panels")
.long("panels")
.num_args(1)
.value_name("N")
.help(
"Sets the number of hex data columns to be displayed. \
Cannot be used with other width-setting options.",
"Sets the number of hex data panels to be displayed. \
`--panels=auto` will display the maximum number of hex data panels \
based on the current terminal width",
),
)
.arg(
Arg::new("group_bytes")
.short('g')
.long("group-bytes")
.num_args(1)
.value_name("N")
.help(
"Sets the number of octets per group to be displayed. \
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. The default base \
is hexadecimal."
)
)
.arg(
Arg::new("terminal_width")
.short('t')
.long("terminal-width")
.takes_value(true)
.num_args(1)
.value_name("N")
.conflicts_with("columns")
.conflicts_with("panels")
.help(
"Sets the number of terminal columns to be displayed.\nSince the terminal \
width may not be an evenly divisible by the width per hex data column, this \
will use the greatest number of hex data columns that can fit in the requested \
will use the greatest number of hex data panels that can fit in the requested \
width but still leave some space to the right.\nCannot be used with other \
width-setting options.",
),
)
.arg(
Arg::new("auto_width")
.short('a')
.long("auto-width")
.conflicts_with_all(&["columns", "terminal_width"])
.help(
"Sets the number of hex data columns to be adjusted according to the \
detected terminal width.\nCannot be used with other width-setting options.",
),
);
let matches = command.get_matches();
let stdin = io::stdin();
let mut reader = match matches.value_of("FILE") {
let mut reader = match matches.get_one::<String>("FILE") {
Some(filename) => Input::File(File::open(filename)?),
None => Input::Stdin(stdin.lock()),
};
let block_size = matches
.value_of("block_size")
.get_one::<String>("block_size")
.map(|bs| {
if let Some(hex_number) = try_parse_as_hex_number(bs) {
return hex_number.map_err(|e| anyhow!(e)).and_then(|x| {
@@ -224,7 +239,7 @@ fn run() -> Result<(), AnyhowError> {
.unwrap_or_else(|| PositiveI64::new(DEFAULT_BLOCK_SIZE).unwrap());
let skip_arg = matches
.value_of("skip")
.get_one::<String>("skip")
.map(|s| {
parse_byte_offset(s, block_size).context(anyhow!(
"failed to parse `--skip` arg {:?} as byte count",
@@ -253,16 +268,16 @@ fn run() -> Result<(), AnyhowError> {
0
};
let parse_byte_count = |s| -> Result<u64, AnyhowError> {
let parse_byte_count = |s| -> Result<u64> {
Ok(parse_byte_offset(s, block_size)?
.assume_forward_offset_from_start()?
.into())
};
let mut reader = if let Some(length) = matches
.value_of("length")
.or_else(|| matches.value_of("bytes"))
.or_else(|| matches.value_of("count"))
.get_one::<String>("length")
.or_else(|| matches.get_one::<String>("bytes"))
.or_else(|| matches.get_one::<String>("count"))
.map(|s| {
parse_byte_count(s).context(anyhow!(
"failed to parse `--length` arg {:?} as byte count",
@@ -276,26 +291,28 @@ fn run() -> Result<(), AnyhowError> {
reader.into_inner()
};
let show_color = match matches.value_of("color") {
let show_color = match matches.get_one::<String>("color").map(String::as_ref) {
Some("never") => false,
Some("auto") => atty::is(Stream::Stdout),
Some("auto") => std::io::stdout().is_terminal(),
_ => true,
};
let border_style = match matches.value_of("border") {
let border_style = match matches.get_one::<String>("border").map(String::as_ref) {
Some("unicode") => BorderStyle::Unicode,
Some("ascii") => BorderStyle::Ascii,
_ => BorderStyle::None,
};
let squeeze = !matches.is_present("nosqueezing");
let &squeeze = matches.get_one::<bool>("nosqueezing").unwrap_or(&true);
let show_char_panel = !matches.is_present("no_chars") && !matches.is_present("plain");
let show_char_panel = *matches.get_one::<bool>("no_chars").unwrap_or(&true)
&& !matches.get_one::<bool>("plain").unwrap_or(&false);
let show_position_panel = !matches.is_present("no_position") && !matches.is_present("plain");
let show_position_panel = *matches.get_one::<bool>("no_position").unwrap_or(&true)
&& !matches.get_one::<bool>("plain").unwrap_or(&false);
let display_offset: u64 = matches
.value_of("display_offset")
.get_one::<String>("display_offset")
.map(|s| {
parse_byte_count(s).context(anyhow!(
"failed to parse `--display-offset` arg {:?} as byte count",
@@ -305,60 +322,118 @@ fn run() -> Result<(), AnyhowError> {
.transpose()?
.unwrap_or(0);
let columns = if let Some(columns) = matches
.value_of("columns")
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 {
((8 / group_bytes) * (base_digits * group_bytes + 1)) + 2 + 8
} else {
((8 / group_bytes) * (base_digits * group_bytes + 1)) + 2
};
if (terminal_width - offset) / col_width < 1 {
1
} else {
(terminal_width - offset) / col_width
}
};
let base = if let Some(base) = matches.get_one::<String>("base")
.map(|s| {
if let Ok(base_num) = s.parse::<u8>() {
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::<String>("group_bytes")
.map(|s| {
s.parse::<NonZeroU16>().map(u16::from).context(anyhow!(
"failed to parse `--columns` arg {:?} as unsigned nonzero integer",
s.parse::<NonZeroU8>().map(u8::from).context(anyhow!(
"failed to parse `--group-bytes`/`-g` arg {:?} as unsigned nonzero integer",
s
))
})
.transpose()?
{
columns
} else {
let terminal_width = if let Some(terminal_width) = matches
.value_of("terminal_width")
.map(|s| {
s.parse::<NonZeroU16>().map(u16::from).context(anyhow!(
"failed to parse `--columns` arg {:?} as unsigned nonzero integer",
s
))
})
.transpose()?
{
Some(terminal_width)
} else if matches.is_present("auto_width") {
Some(terminal_size().ok_or_else(|| anyhow!("not a TTY"))?.0 .0)
if (group_bytes <= 8) && ((group_bytes & (group_bytes - 1)) == 0) {
group_bytes
} else {
None
};
if let Some(terminal_width) = terminal_width {
let offset = if show_position_panel { 10 } else { 1 };
let col_width = if show_char_panel { 35 } else { 26 };
if (terminal_width - offset) / col_width < 1 {
1
} else {
(terminal_width - offset) / col_width
}
} else {
2
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::<String>("panels").map(String::as_ref) == Some("auto") {
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::<String>("panels")
.map(|s| {
s.parse::<NonZeroU64>().map(u64::from).context(anyhow!(
"failed to parse `--panels` arg {:?} as unsigned nonzero integer",
s
))
})
.transpose()?
{
panels
} else if let Some(terminal_width) = matches
.get_one::<String>("terminal_width")
.map(|s| {
s.parse::<NonZeroU64>().map(u64::from).context(anyhow!(
"failed to parse `--terminal-width` arg {:?} as unsigned nonzero integer",
s
))
})
.transpose()?
{
max_panels_fn(terminal_width, base_digits, group_bytes.into())
} else {
2
};
let stdout = io::stdout();
let mut stdout_lock = stdout.lock();
let mut stdout_lock = BufWriter::new(stdout.lock());
let mut printer = Printer::new(
&mut stdout_lock,
show_color,
show_char_panel,
show_position_panel,
border_style,
squeeze,
columns,
);
let mut printer = PrinterBuilder::new(&mut stdout_lock)
.show_color(show_color)
.show_char_panel(show_char_panel)
.show_position_panel(show_position_panel)
.with_border_style(border_style)
.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))?;
@@ -366,13 +441,14 @@ fn run() -> Result<(), AnyhowError> {
}
fn main() {
// Enable ANSI support for Windows
#[cfg(windows)]
let _ = ansi_term::enable_ansi_support();
let result = run();
if let Err(err) = result {
if let Some(io_error) = err.downcast_ref::<io::Error>() {
if io_error.kind() == ::std::io::ErrorKind::BrokenPipe {
std::process::exit(0);
}
}
eprintln!("Error: {:?}", err);
std::process::exit(1);
}
+541 -282
View File
@@ -1,23 +1,36 @@
pub(crate) mod input;
pub mod squeezer;
pub use input::*;
use std::io::{self, Read, Write};
use std::io::{self, BufReader, Read, Write};
use ansi_term::Color;
use ansi_term::Color::Fixed;
use anstyle::{AnsiColor, Reset};
use crate::squeezer::{SqueezeAction, Squeezer};
pub enum Base {
Binary,
Octal,
Decimal,
Hexadecimal,
}
const BUFFER_SIZE: usize = 256;
#[derive(PartialEq, Eq)]
#[repr(usize)]
enum ByteColor {
Null = 0,
Offset = 1,
AsciiPrintable = 2,
AsciiWhitespace = 3,
AsciiOther = 4,
NonAscii = 5,
Reset = 6,
}
const COLOR_NULL: Color = Fixed(242); // grey
const COLOR_OFFSET: Color = Fixed(242); // grey
const COLOR_ASCII_PRINTABLE: Color = Color::Cyan;
const COLOR_ASCII_WHITESPACE: Color = Color::Green;
const COLOR_ASCII_OTHER: Color = Color::Purple;
const COLOR_NONASCII: Color = Color::Yellow;
const COLOR_NULL: AnsiColor = AnsiColor::BrightBlack;
const COLOR_OFFSET: AnsiColor = AnsiColor::BrightBlack;
const COLOR_ASCII_PRINTABLE: AnsiColor = AnsiColor::Cyan;
const COLOR_ASCII_WHITESPACE: AnsiColor = AnsiColor::Green;
const COLOR_ASCII_OTHER: AnsiColor = AnsiColor::Magenta;
const COLOR_NONASCII: AnsiColor = AnsiColor::Yellow;
pub enum ByteCategory {
Null,
@@ -27,6 +40,14 @@ pub enum ByteCategory {
NonAscii,
}
#[derive(PartialEq)]
enum Squeezer {
Print,
Delete,
Ignore,
Disabled,
}
#[derive(Copy, Clone)]
struct Byte(u8);
@@ -45,15 +66,15 @@ impl Byte {
}
}
fn color(self) -> &'static Color {
fn color(self) -> ByteColor {
use crate::ByteCategory::*;
match self.category() {
Null => &COLOR_NULL,
AsciiPrintable => &COLOR_ASCII_PRINTABLE,
AsciiWhitespace => &COLOR_ASCII_WHITESPACE,
AsciiOther => &COLOR_ASCII_OTHER,
NonAscii => &COLOR_NONASCII,
Null => ByteColor::Null,
AsciiPrintable => ByteColor::AsciiPrintable,
AsciiWhitespace => ByteColor::AsciiWhitespace,
AsciiOther => ByteColor::AsciiOther,
NonAscii => ByteColor::NonAscii,
}
}
@@ -61,7 +82,7 @@ impl Byte {
use crate::ByteCategory::*;
match self.category() {
Null => '0',
Null => '⋄',
AsciiPrintable => self.0 as char,
AsciiWhitespace if self.0 == 0x20 => ' ',
AsciiWhitespace => '_',
@@ -78,6 +99,7 @@ struct BorderElements {
right_corner: char,
}
#[derive(Clone, Copy)]
pub enum BorderStyle {
Unicode,
Ascii,
@@ -138,73 +160,175 @@ impl BorderStyle {
}
}
pub struct Printer<'a, Writer: Write> {
idx: u64,
/// The raw bytes used as input for the current line.
raw_line: Vec<u8>,
/// The buffered line built with each byte, ready to print to writer.
buffer_line: Vec<u8>,
pub struct PrinterBuilder<'a, Writer: Write> {
writer: &'a mut Writer,
show_color: bool,
show_char_panel: bool,
show_position_panel: bool,
border_style: BorderStyle,
header_was_printed: bool,
use_squeeze: bool,
panels: u64,
group_bytes: u8,
base: Base,
}
impl<'a, Writer: Write> PrinterBuilder<'a, Writer> {
pub fn new(writer: &'a mut Writer) -> Self {
PrinterBuilder {
writer,
show_color: true,
show_char_panel: true,
show_position_panel: true,
border_style: BorderStyle::Unicode,
use_squeeze: true,
panels: 2,
group_bytes: 1,
base: Base::Hexadecimal,
}
}
pub fn show_color(mut self, show_color: bool) -> Self {
self.show_color = show_color;
self
}
pub fn show_char_panel(mut self, show_char_panel: bool) -> Self {
self.show_char_panel = show_char_panel;
self
}
pub fn show_position_panel(mut self, show_position_panel: bool) -> Self {
self.show_position_panel = show_position_panel;
self
}
pub fn with_border_style(mut self, border_style: BorderStyle) -> Self {
self.border_style = border_style;
self
}
pub fn enable_squeezing(mut self, enable: bool) -> Self {
self.use_squeeze = enable;
self
}
pub fn num_panels(mut self, num: u64) -> Self {
self.panels = num;
self
}
pub fn num_group_bytes(mut self, num: u8) -> Self {
self.group_bytes = num;
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,
self.show_color,
self.show_char_panel,
self.show_position_panel,
self.border_style,
self.use_squeeze,
self.panels,
self.group_bytes,
self.base,
)
}
}
pub struct Printer<'a, Writer: Write> {
idx: u64,
/// the buffer containing all the bytes in a line for character printing
line_buf: Vec<u8>,
writer: &'a mut Writer,
show_char_panel: bool,
show_position_panel: bool,
show_color: bool,
colors: Vec<String>,
curr_color: Option<ByteColor>,
border_style: BorderStyle,
byte_hex_panel: Vec<String>,
byte_char_panel: Vec<String>,
// same as previous but in Fixed(242) gray color, for position panel
byte_hex_panel_g: Vec<String>,
byte_char_panel_g: Vec<String>,
squeezer: Squeezer,
display_offset: u64,
/// The number of panels to draw.
columns: u16,
panels: u64,
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> {
pub fn new(
fn new(
writer: &'a mut Writer,
show_color: bool,
show_char_panel: bool,
show_position_panel: bool,
border_style: BorderStyle,
use_squeeze: bool,
columns: u16,
panels: u64,
group_bytes: u8,
base: Base,
) -> Printer<'a, Writer> {
Printer {
idx: 1,
raw_line: vec![],
buffer_line: vec![],
idx: 0,
line_buf: vec![0x0; 8 * panels as usize],
writer,
show_color,
show_char_panel,
show_position_panel,
show_color,
curr_color: None,
colors: vec![
COLOR_NULL.render_fg().to_string(),
COLOR_OFFSET.render_fg().to_string(),
COLOR_ASCII_PRINTABLE.render_fg().to_string(),
COLOR_ASCII_WHITESPACE.render_fg().to_string(),
COLOR_ASCII_OTHER.render_fg().to_string(),
COLOR_NONASCII.render_fg().to_string(),
Reset.render().to_string(),
],
border_style,
header_was_printed: false,
byte_hex_panel: (0u8..=u8::MAX)
.map(|i| {
let byte_hex = format!("{:02x} ", i);
if show_color {
Byte(i).color().paint(byte_hex).to_string()
} else {
byte_hex
}
.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: show_char_panel
.then(|| {
(0u8..=u8::MAX)
.map(|i| {
let byte_char = format!("{}", Byte(i).as_char());
if show_color {
Byte(i).color().paint(byte_char).to_string()
} else {
byte_char
}
})
.collect()
})
.unwrap_or_default(),
squeezer: Squeezer::new(use_squeeze, 8 * columns as u64),
byte_char_panel: (0u8..=u8::MAX)
.map(|i| format!("{}", Byte(i).as_char()))
.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(),
squeezer: if use_squeeze {
Squeezer::Ignore
} else {
Squeezer::Disabled
},
display_offset: 0,
columns,
panels,
squeeze_byte: 0x00,
group_bytes,
base_digits: match base {
Base::Binary => 8,
Base::Octal => 3,
Base::Decimal => 3,
Base::Hexadecimal => 2,
},
}
}
@@ -213,13 +337,21 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
self
}
fn write_border(&mut self, border_elements: BorderElements) {
fn panel_sz(&self) -> usize {
// add one to include the trailing space of a group
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
}
fn write_border(&mut self, border_elements: BorderElements) -> io::Result<()> {
let h = border_elements.horizontal_line;
let c = border_elements.column_separator;
let l = border_elements.left_corner;
let r = border_elements.right_corner;
let h8 = h.to_string().repeat(8);
let h25 = h.to_string().repeat(25);
let h_repeat = h.to_string().repeat(self.panel_sz());
if self.show_position_panel {
write!(self.writer, "{l}{h8}{c}", l = l, c = c, h8 = h8).ok();
@@ -227,280 +359,342 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
write!(self.writer, "{}", l).ok();
}
for _ in 0..self.columns - 1 {
write!(self.writer, "{h25}{c}", h25 = h25, c = c).ok();
for _ in 0..self.panels - 1 {
write!(self.writer, "{h_repeat}{c}", h_repeat = h_repeat, c = c).ok();
}
if self.show_char_panel {
write!(self.writer, "{h25}{c}", h25 = h25, c = c).ok();
write!(self.writer, "{h_repeat}{c}", h_repeat = h_repeat, c = c).ok();
} else {
write!(self.writer, "{h25}", h25 = h25).ok();
write!(self.writer, "{h_repeat}", h_repeat = h_repeat).ok();
}
if self.show_char_panel {
for _ in 0..self.columns - 1 {
for _ in 0..self.panels - 1 {
write!(self.writer, "{h8}{c}", h8 = h8, c = c).ok();
}
writeln!(self.writer, "{h8}{r}", h8 = h8, r = r).ok();
} else {
writeln!(self.writer, "{r}", r = r).ok();
}
Ok(())
}
pub fn print_header(&mut self) {
if self.header_was_printed {
return;
}
pub fn print_header(&mut self) -> io::Result<()> {
if let Some(e) = self.border_style.header_elems() {
self.write_border(e)
self.write_border(e)?
}
self.header_was_printed = true;
Ok(())
}
pub fn print_footer(&mut self) {
pub fn print_footer(&mut self) -> io::Result<()> {
if let Some(e) = self.border_style.footer_elems() {
self.write_border(e)
self.write_border(e)?
}
}
fn print_position_panel(&mut self) {
if !self.show_position_panel {
write!(&mut self.buffer_line, "{} ", self.border_style.outer_sep()).ok();
return;
}
let style = COLOR_OFFSET.normal();
let byte_index = format!("{:08x}", self.idx - 1 + self.display_offset);
let formatted_string = if self.show_color {
format!("{}", style.paint(byte_index))
} else {
byte_index
};
let _ = write!(
&mut self.buffer_line,
"{}{}{} ",
self.border_style.outer_sep(),
formatted_string,
self.border_style.outer_sep()
);
}
pub fn print_char_panel(&mut self) {
if !self.show_char_panel {
// just write newline if character panel is hidden
writeln!(&mut self.buffer_line).ok();
return;
}
let len = self.raw_line.len();
let mut idx = 1;
for &b in self.raw_line.iter() {
let _ = write!(
&mut self.buffer_line,
"{}",
self.byte_char_panel[b as usize]
);
if idx % 8 == 0 && idx % (u64::from(self.columns) * 8) != 0 {
let _ = write!(&mut self.buffer_line, "{}", self.border_style.inner_sep());
}
idx += 1;
}
if len < usize::from(8 * self.columns) {
let _ = write!(&mut self.buffer_line, "{0:1$}", "", 8 - len % 8);
for _ in 0..(usize::from(8 * self.columns) - (len + (8 - len % 8))) / 8 {
let _ = write!(
&mut self.buffer_line,
"{2}{0:1$}",
"",
8,
self.border_style.inner_sep()
);
}
}
let _ = writeln!(&mut self.buffer_line, "{}", self.border_style.outer_sep());
}
pub fn print_byte(&mut self, b: u8) -> io::Result<()> {
if self.idx % (u64::from(self.columns) * 8) == 1 {
self.print_header();
self.print_position_panel();
}
write!(&mut self.buffer_line, "{}", self.byte_hex_panel[b as usize])?;
self.raw_line.push(b);
self.squeezer.process(b, self.idx);
if self.idx % (u64::from(self.columns) * 8) == 0 {
self.print_textline()?;
} else if self.idx % 8 == 0 {
let _ = write!(&mut self.buffer_line, "{} ", self.border_style.inner_sep());
}
self.idx += 1;
Ok(())
}
pub fn print_textline(&mut self) -> io::Result<()> {
let len = self.raw_line.len();
if len == 0 {
if self.squeezer.active() {
self.print_position_panel();
write!(&mut self.buffer_line, "{0:1$}", "", 24)?;
for _ in 0..self.columns - 1 {
write!(
&mut self.buffer_line,
"{2}{0:1$}",
"",
25,
self.border_style.inner_sep()
)?;
}
write!(
&mut self.buffer_line,
"{2}{0:1$}",
"",
8,
self.border_style.outer_sep()
)?;
for _ in 0..self.columns - 1 {
write!(
&mut self.buffer_line,
"{2}{0:1$}",
"",
8,
self.border_style.inner_sep()
)?;
}
writeln!(&mut self.buffer_line, "{}", self.border_style.outer_sep())?;
self.writer.write_all(&self.buffer_line)?;
}
return Ok(());
fn print_position_panel(&mut self) -> io::Result<()> {
self.writer.write_all(
self.border_style
.outer_sep()
.encode_utf8(&mut [0; 4])
.as_bytes(),
)?;
if self.show_color {
self.writer
.write_all(self.colors[ByteColor::Offset as usize].as_bytes())?;
}
let squeeze_action = self.squeezer.action();
// print empty space on last line
if squeeze_action != SqueezeAction::Delete {
if len < usize::from(8 * self.columns) {
write!(&mut self.buffer_line, "{0:1$}", "", 3 * (8 - len % 8))?;
for _ in 0..(usize::from(8 * self.columns) - (len + (8 - len % 8))) / 8 {
write!(
&mut self.buffer_line,
"{2}{0:1$}",
"",
1 + 3 * 8,
self.border_style.inner_sep()
)?;
if self.show_position_panel {
match self.squeezer {
Squeezer::Print => {
self.writer
.write_all(self.byte_char_panel_g[b'*' as usize].as_bytes())?;
if self.show_color {
self.writer
.write_all(self.colors[ByteColor::Reset as usize].as_bytes())?;
}
self.writer.write_all(b" ")?;
}
Squeezer::Ignore | Squeezer::Disabled | Squeezer::Delete => {
let byte_index: [u8; 8] = (self.idx + self.display_offset).to_be_bytes();
let mut i = 0;
while byte_index[i] == 0x0 && i < 4 {
i += 1;
}
for &byte in byte_index.iter().skip(i) {
self.writer
.write_all(self.byte_hex_panel_g[byte as usize].as_bytes())?;
}
if self.show_color {
self.writer
.write_all(self.colors[ByteColor::Reset as usize].as_bytes())?;
}
}
}
write!(&mut self.buffer_line, "{}", self.border_style.outer_sep())?;
self.writer.write_all(
self.border_style
.outer_sep()
.encode_utf8(&mut [0; 4])
.as_bytes(),
)?;
}
self.print_char_panel();
Ok(())
}
match squeeze_action {
SqueezeAction::Print => {
self.buffer_line.clear();
let style = COLOR_OFFSET.normal();
let asterisk = if self.show_color {
format!("{}", style.paint("*"))
fn print_char(&mut self, i: u64) -> io::Result<()> {
match self.squeezer {
Squeezer::Print | Squeezer::Delete => self.writer.write_all(b" ")?,
Squeezer::Ignore | Squeezer::Disabled => {
if let Some(&b) = self.line_buf.get(i as usize) {
if self.show_color && self.curr_color != Some(Byte(b).color()) {
self.writer
.write_all(self.colors[Byte(b).color() as usize].as_bytes())?;
self.curr_color = Some(Byte(b).color());
}
self.writer
.write_all(self.byte_char_panel[b as usize].as_bytes())?;
} else {
String::from("*")
};
write!(
&mut self.buffer_line,
"{3}{0}{1:2$}{3}",
asterisk,
"",
7,
self.border_style.outer_sep()
)?;
for i in 0..self.columns {
write!(&mut self.buffer_line, "{0:1$}", "", 25)?;
if i != self.columns - 1 {
write!(&mut self.buffer_line, "{}", self.border_style.inner_sep())?;
} else {
write!(&mut self.buffer_line, "{}", self.border_style.outer_sep())?;
}
}
for i in 0..self.columns {
write!(&mut self.buffer_line, "{0:1$}", "", 8)?;
if i != self.columns - 1 {
write!(&mut self.buffer_line, "{}", self.border_style.inner_sep())?;
} else {
writeln!(&mut self.buffer_line, "{}", self.border_style.outer_sep())?;
}
self.squeezer = Squeezer::Print;
}
}
SqueezeAction::Delete => self.buffer_line.clear(),
SqueezeAction::Ignore => (),
}
self.writer.write_all(&self.buffer_line)?;
self.raw_line.clear();
self.buffer_line.clear();
self.squeezer.advance();
if i == 8 * self.panels - 1 {
if self.show_color {
self.writer
.write_all(self.colors[ByteColor::Reset as usize].as_bytes())?;
self.curr_color = None;
}
self.writer.write_all(
self.border_style
.outer_sep()
.encode_utf8(&mut [0; 4])
.as_bytes(),
)?;
} else if i % 8 == 7 {
if self.show_color {
self.writer
.write_all(self.colors[ByteColor::Reset as usize].as_bytes())?;
self.curr_color = None;
}
self.writer.write_all(
self.border_style
.inner_sep()
.encode_utf8(&mut [0; 4])
.as_bytes(),
)?;
}
Ok(())
}
pub fn header_was_printed(&self) -> bool {
self.header_was_printed
pub fn print_char_panel(&mut self) -> io::Result<()> {
for i in 0..self.line_buf.len() {
self.print_char(i as u64)?;
}
Ok(())
}
fn print_byte(&mut self, i: usize, b: u8) -> io::Result<()> {
match self.squeezer {
Squeezer::Print => {
if !self.show_position_panel && i == 0 {
if self.show_color {
self.writer
.write_all(self.colors[ByteColor::Offset as usize].as_bytes())?;
}
self.writer
.write_all(self.byte_char_panel_g[b'*' as usize].as_bytes())?;
if self.show_color {
self.writer
.write_all(self.colors[ByteColor::Reset as usize].as_bytes())?;
}
} else {
if i % (self.group_bytes as usize) == 0 {
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 => {
if i % (self.group_bytes as usize) == 0 {
self.writer.write_all(b" ")?;
}
if self.show_color && self.curr_color != Some(Byte(b).color()) {
self.writer
.write_all(self.colors[Byte(b).color() as usize].as_bytes())?;
self.curr_color = Some(Byte(b).color());
}
self.writer
.write_all(self.byte_hex_panel[b as usize].as_bytes())?;
}
}
// byte is last in panel
if i % 8 == 7 {
if self.show_color {
self.curr_color = None;
self.writer
.write_all(self.colors[ByteColor::Reset as usize].as_bytes())?;
}
self.writer.write_all(b" ")?;
// byte is last in last panel
if i as u64 % (8 * self.panels) == 8 * self.panels - 1 {
self.writer.write_all(
self.border_style
.outer_sep()
.encode_utf8(&mut [0; 4])
.as_bytes(),
)?;
} else {
self.writer.write_all(
self.border_style
.inner_sep()
.encode_utf8(&mut [0; 4])
.as_bytes(),
)?;
}
}
Ok(())
}
pub fn print_bytes(&mut self) -> io::Result<()> {
for (i, &b) in self.line_buf.clone().iter().enumerate() {
self.print_byte(i, b)?;
}
Ok(())
}
/// Loop through the given `Reader`, printing until the `Reader` buffer
/// is exhausted.
pub fn print_all<Reader: Read>(
&mut self,
mut reader: Reader,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let mut buffer = [0; BUFFER_SIZE];
'mainloop: loop {
let size = reader.read(&mut buffer)?;
if size == 0 {
break;
}
pub fn print_all<Reader: Read>(&mut self, reader: Reader) -> io::Result<()> {
let mut is_empty = true;
for b in &buffer[..size] {
let res = self.print_byte(*b);
let mut buf = BufReader::new(reader);
if res.is_err() {
// Broken pipe
break 'mainloop;
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..]) {
self.line_buf.resize(n, 0);
break Some(n);
};
} else if n == 0 {
// if no bytes are read, that indicates end of file
if self.squeezer == Squeezer::Delete {
// empty the last line when ending is squeezed
self.line_buf.clear();
break Some(0);
}
break None;
}
}
}
if is_empty {
self.print_header()?;
is_empty = false;
}
// Finish last line
self.print_textline().ok();
// squeeze is active, check if the line is the same
// skip print if still squeezed, otherwise print and deactivate squeeze
if matches!(self.squeezer, Squeezer::Print | Squeezer::Delete) {
if self
.line_buf
.chunks_exact(std::mem::size_of::<usize>())
.all(|w| usize::from_ne_bytes(w.try_into().unwrap()) == self.squeeze_byte)
{
if self.squeezer == Squeezer::Delete {
self.idx += 8 * self.panels;
continue;
}
} else {
self.squeezer = Squeezer::Ignore;
}
}
if !self.header_was_printed() {
self.print_header();
// print the line
self.print_position_panel()?;
self.print_bytes()?;
if self.show_char_panel {
self.print_char_panel()?;
}
self.writer.write_all(b"\n")?;
// increment index to next line
self.idx += 8 * self.panels;
// change from print to delete if squeeze is still active
if self.squeezer == Squeezer::Print {
self.squeezer = Squeezer::Delete;
}
// repeat the first byte in the line until it's a usize
// compare that usize with each usize chunk in the line
// if they are all the same, change squeezer to print
let repeat_byte = (self.line_buf[0] as usize) * (usize::MAX / 255);
if !matches!(self.squeezer, Squeezer::Disabled | Squeezer::Delete)
&& self
.line_buf
.chunks_exact(std::mem::size_of::<usize>())
.all(|w| usize::from_ne_bytes(w.try_into().unwrap()) == repeat_byte)
{
self.squeezer = Squeezer::Print;
self.squeeze_byte = repeat_byte;
};
};
// special ending
if is_empty {
self.base_digits = 2;
self.print_header()?;
if self.show_position_panel {
write!(self.writer, "{0:9}", "│").ok();
write!(self.writer, "{0:9}", "│")?;
}
write!(
self.writer,
"{0:2}{1:24}{0}{0:>26}",
"│", "No content to print"
)
.ok();
"{0:2}{1:2$}{0}{0:>3$}",
"│",
"No content",
self.panel_sz() - 1,
self.panel_sz() + 1,
)?;
if self.show_char_panel {
write!(self.writer, "{0:>9}{0:>9}", "│").ok();
write!(self.writer, "{0:>9}{0:>9}", "│")?;
}
writeln!(self.writer).ok();
writeln!(self.writer)?;
} else if let Some(n) = leftover {
// last line is incomplete
self.print_position_panel()?;
self.squeezer = Squeezer::Ignore;
self.print_bytes()?;
self.squeezer = Squeezer::Print;
for i in n..8 * self.panels as usize {
self.print_byte(i, 0)?;
}
if self.show_char_panel {
self.squeezer = Squeezer::Ignore;
self.print_char_panel()?;
self.squeezer = Squeezer::Print;
for i in n..8 * self.panels as usize {
self.print_char(i as u64)?;
}
}
self.writer.write_all(b"\n")?;
}
self.print_footer();
self.print_footer()?;
self.writer.flush()?;
Ok(())
}
@@ -523,6 +717,8 @@ mod tests {
BorderStyle::Unicode,
true,
2,
1,
Base::Hexadecimal,
);
printer.print_all(input).unwrap();
@@ -536,7 +732,7 @@ mod tests {
let input = io::empty();
let expected_string = "\
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
│ │ No content to print │ │ │ │
│ │ No content │ │ │ │
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘
"
.to_owned();
@@ -575,6 +771,8 @@ mod tests {
BorderStyle::Unicode,
true,
2,
1,
Base::Hexadecimal,
);
printer.display_offset(0xdeadbeef);
@@ -585,7 +783,7 @@ mod tests {
}
#[test]
fn multiple_columns() {
fn multiple_panels() {
let input = io::Cursor::new(b"supercalifragilisticexpialidocioussupercalifragilisticexpialidocioussupercalifragilisticexpialidocious");
let expected_string = "\
┌────────┬─────────────────────────┬─────────────────────────┬─────────────────────────┬─────────────────────────┬────────┬────────┬────────┬────────┐
@@ -606,6 +804,67 @@ mod tests {
BorderStyle::Unicode,
true,
4,
1,
Base::Hexadecimal,
);
printer.print_all(input).unwrap();
let actual_string: &str = str::from_utf8(&output).unwrap();
assert_eq!(actual_string, expected_string)
}
#[test]
fn squeeze_works() {
let input = io::Cursor::new(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00");
let expected_string = "\
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
│00000000│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│* │ ┊ │ ┊ │
│00000020│ 00 ┊ │⋄ ┊ │
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘
"
.to_owned();
assert_print_all_output(input, expected_string);
}
#[test]
fn squeeze_nonzero() {
let input = io::Cursor::new(b"000000000000000000000000000000000");
let expected_string = "\
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
│00000000│ 30 30 30 30 30 30 30 30 ┊ 30 30 30 30 30 30 30 30 │00000000┊00000000│
│* │ ┊ │ ┊ │
│00000020│ 30 ┊ │0 ┊ │
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘
"
.to_owned();
assert_print_all_output(input, expected_string);
}
#[test]
fn squeeze_multiple_panels() {
let input = io::Cursor::new(b"0000000000000000000000000000000000000000000000000");
let expected_string = "\
┌────────┬─────────────────────────┬─────────────────────────┬─────────────────────────┬────────┬────────┬────────┐
│00000000│ 30 30 30 30 30 30 30 30 ┊ 30 30 30 30 30 30 30 30 ┊ 30 30 30 30 30 30 30 30 │00000000┊00000000┊00000000│
│* │ ┊ ┊ │ ┊ ┊ │
│00000030│ 30 ┊ ┊ │0 ┊ ┊ │
└────────┴─────────────────────────┴─────────────────────────┴─────────────────────────┴────────┴────────┴────────┘
"
.to_owned();
let mut output = vec![];
let mut printer: Printer<Vec<u8>> = Printer::new(
&mut output,
false,
true,
true,
BorderStyle::Unicode,
true,
3,
1,
Base::Hexadecimal,
);
printer.print_all(input).unwrap();
-407
View File
@@ -1,407 +0,0 @@
#[derive(Debug, PartialEq)]
enum SqueezeState {
/// not enabled
Disabled,
/// Will be set from all states if equal condition can't be hold up.
/// Set if previous byte is not equal the current processed byte.
NoSqueeze,
/// Valid for a whole line to identify if it is candidate for squeezing
Probe,
/// Squeeze line parsing is active, but EOL is not reached yet
SqueezeActive,
/// Squeeze line, EOL is reached, will influence the action
Squeeze,
/// same as Squeeze, however this is only for the first line after
/// the squeeze candidate has been set.
SqueezeFirstLine,
/// same as SqueezeActive, however this is only for the first line after
/// the squeeze candidate has been set.
SqueezeActiveFirstLine,
}
pub struct Squeezer {
state: SqueezeState,
byte: u8,
lsize: u64,
}
#[derive(Debug, PartialEq)]
pub enum SqueezeAction {
Ignore,
Print,
Delete,
}
impl Squeezer {
pub fn new(enabled: bool, lsize: u64) -> Squeezer {
Squeezer {
state: if enabled {
SqueezeState::Probe
} else {
SqueezeState::Disabled
},
byte: 0,
lsize,
}
}
pub fn process(&mut self, b: u8, i: u64) {
use self::SqueezeState::*;
if self.state == Disabled {
return;
}
let eq = b == self.byte;
if i % self.lsize == 0 {
if !eq {
self.state = Probe;
} else {
self.state = match self.state {
NoSqueeze => Probe,
Probe => SqueezeActiveFirstLine,
SqueezeActiveFirstLine => SqueezeFirstLine,
SqueezeFirstLine => SqueezeActive,
SqueezeActive => Squeeze,
Squeeze => SqueezeActive,
Disabled => Disabled,
};
}
} else if !eq {
if i % self.lsize == 1 {
self.state = Probe;
} else if i % self.lsize != 1 {
self.state = NoSqueeze;
}
}
self.byte = b;
}
pub fn active(&self) -> bool {
use self::SqueezeState::*;
matches!(
self.state,
Squeeze | SqueezeActive | SqueezeFirstLine | SqueezeActiveFirstLine
)
}
pub fn action(&self) -> SqueezeAction {
match self.state {
SqueezeState::SqueezeFirstLine => SqueezeAction::Print,
SqueezeState::Squeeze => SqueezeAction::Delete,
_ => SqueezeAction::Ignore,
}
}
pub fn advance(&mut self) {
match self.state {
SqueezeState::SqueezeFirstLine => {
self.state = SqueezeState::SqueezeActive;
}
SqueezeState::Squeeze => {
self.state = SqueezeState::SqueezeActive;
}
_ => {}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
const LSIZE: u64 = 16;
const LSIZE_USIZE: usize = LSIZE as usize;
#[test]
fn three_same_lines() {
const LINES: usize = 3;
let v = vec![0u8; LINES * LSIZE_USIZE];
let mut s = Squeezer::new(true, LSIZE);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
let exp = vec![
SqueezeAction::Ignore, // first line, print as is
SqueezeAction::Print, // print squeeze symbol
SqueezeAction::Delete, // delete reoccurring line
];
let mut idx = 1;
for (line, z) in v.chunks(LSIZE_USIZE).enumerate() {
for i in z {
s.process(*i, idx);
idx += 1;
}
let action = s.action();
s.advance();
assert_eq!(action, exp[line]);
}
}
#[test]
fn incomplete_while_squeeze() {
// fourth line only has 12 bytes and should be printed
let v = vec![0u8; 3 * LSIZE_USIZE + 12];
let mut s = Squeezer::new(true, LSIZE);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
let exp = vec![
SqueezeAction::Ignore, // first line, print as is
SqueezeAction::Print, // print squeeze symbol
SqueezeAction::Delete, // delete reoccurring line
SqueezeAction::Ignore, // last line only 12 bytes, print it
];
let mut idx = 1;
for (line, z) in v.chunks(LSIZE_USIZE).enumerate() {
for i in z {
s.process(*i, idx);
idx += 1;
}
assert_eq!(s.action(), exp[line]);
s.advance();
}
}
#[test]
/// all three lines are different, print all
fn three_different_lines() {
let mut v: Vec<u8> = vec![];
v.extend(vec![0u8; 16]);
v.extend(vec![1u8; 16]);
v.extend(vec![2u8; 16]);
let mut s = Squeezer::new(true, LSIZE);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
let exp = vec![
SqueezeAction::Ignore, // first line, print as is
SqueezeAction::Ignore, // different
SqueezeAction::Ignore, // different
];
let mut idx = 1;
for (line, z) in v.chunks(LSIZE_USIZE).enumerate() {
for i in z {
s.process(*i, idx);
idx += 1;
}
let action = s.action();
assert_eq!(action, exp[line]);
s.advance();
}
}
#[test]
/// first two lines same, hence squeeze symbol, third line diff, hence
/// print
fn one_squeeze_no_delete() {
const LINES: usize = 3;
let mut v = vec![0u8; (LINES - 1) * LSIZE_USIZE];
v.extend(vec![1u8; 16]);
let mut s = Squeezer::new(true, LSIZE);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
let exp = vec![
SqueezeAction::Ignore, // first line, print as is
SqueezeAction::Print, // print squeeze symbol
SqueezeAction::Ignore, // different lines, print again
];
let mut idx = 1;
for (line, z) in v.chunks(LSIZE_USIZE).enumerate() {
for i in z {
s.process(*i, idx);
idx += 1;
}
let action = s.action();
s.advance();
assert_eq!(action, exp[line]);
}
}
#[test]
/// First line all eq, 2nd half eq with first line, then change
fn second_line_different() {
const LINES: usize = 2;
let mut v = vec![0u8; (LINES - 1) * LSIZE_USIZE];
v.extend(vec![0u8; 8]);
v.extend(vec![1u8; 8]);
let mut s = Squeezer::new(true, LSIZE);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
let exp = vec![
SqueezeAction::Ignore, // first line, print as is
SqueezeAction::Ignore, // print squeeze symbol
];
let mut idx = 1;
for (line, z) in v.chunks(LSIZE_USIZE).enumerate() {
for i in z {
s.process(*i, idx);
idx += 1;
}
let action = s.action();
s.advance();
assert_eq!(action, exp[line]);
}
}
#[test]
/// all three lines never become squeeze candidate (diff within line)
fn never_squeeze_candidate() {
let mut v = vec![];
v.extend(vec![0u8; 8]);
v.extend(vec![1u8; 8]);
v.extend(vec![0u8; 8]);
v.extend(vec![1u8; 8]);
v.extend(vec![0u8; 8]);
v.extend(vec![1u8; 8]);
let mut s = Squeezer::new(true, LSIZE);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
let exp = vec![
SqueezeAction::Ignore, // first line, print as is
SqueezeAction::Ignore, // print squeeze symbol
SqueezeAction::Ignore, // print squeeze symbol
];
let mut idx = 1;
for (line, z) in v.chunks(LSIZE_USIZE).enumerate() {
for i in z {
s.process(*i, idx);
idx += 1;
}
let action = s.action();
s.advance();
assert_eq!(action, exp[line]);
}
}
#[test]
fn mix_everything() {
let mut v = vec![];
v.extend(vec![10u8; 16]); // print
v.extend(vec![20u8; 16]); // print
v.extend(vec![0u8; 16]); // print
v.extend(vec![0u8; 16]); // *
v.extend(vec![10u8; 16]); // print
v.extend(vec![20u8; 16]); // print
v.extend(vec![0u8; 16]); // print
v.extend(vec![0u8; 16]); // *
v.extend(vec![0u8; 16]); // delete
v.extend(vec![0u8; 16]); // delete*
v.extend(vec![20u8; 16]); // print
v.extend(vec![0u8; 12]); // print, only 12 bytes
let mut s = Squeezer::new(true, LSIZE);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
let exp = vec![
SqueezeAction::Ignore,
SqueezeAction::Ignore,
SqueezeAction::Ignore,
SqueezeAction::Print,
SqueezeAction::Ignore,
SqueezeAction::Ignore,
SqueezeAction::Ignore,
SqueezeAction::Print,
SqueezeAction::Delete,
SqueezeAction::Delete,
SqueezeAction::Ignore,
SqueezeAction::Ignore,
];
let mut idx = 1;
for (line, z) in v.chunks(LSIZE_USIZE).enumerate() {
for i in z {
s.process(*i, idx);
idx += 1;
}
let action = s.action();
s.advance();
assert_eq!(action, exp[line]);
}
}
#[test]
fn last_char_diff() {
// see issue #62
let mut v = vec![];
v.extend(vec![20u8; 16]);
v.extend(vec![20u8; 15]);
v.push(61);
v.extend(vec![20u8; 16]);
v.extend(vec![20u8; 16]);
let mut s = Squeezer::new(true, LSIZE);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
let exp = vec![
SqueezeAction::Ignore, // print as is
SqueezeAction::Ignore, // print as is
SqueezeAction::Ignore, // print as is
SqueezeAction::Print, // print '*' char
];
let mut idx = 1;
for (line, z) in v.chunks(LSIZE_USIZE).enumerate() {
for i in z {
s.process(*i, idx);
idx += 1;
}
assert_eq!(s.action(), exp[line]);
s.advance();
}
}
#[test]
fn first_char_diff() {
// see issue #62
let mut v = vec![];
v.extend(vec![20u8; 16]);
v.push(61);
v.extend(vec![20u8; 15]);
v.extend(vec![20u8; 16]);
let mut s = Squeezer::new(true, LSIZE);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
let exp = vec![
SqueezeAction::Ignore, // print as is
SqueezeAction::Ignore, // print as is
SqueezeAction::Ignore, // print as is
];
let mut idx = 1;
for (line, z) in v.chunks(LSIZE_USIZE).enumerate() {
for i in z {
s.process(*i, idx);
idx += 1;
}
assert_eq!(s.action(), exp[line]);
s.advance();
}
}
}
+304 -6
View File
@@ -1,10 +1,30 @@
use assert_cmd::Command;
fn hexyl() -> Command {
let mut cmd = Command::new(assert_cmd::cargo_bin!("hexyl"));
let mut cmd = Command::cargo_bin("hexyl").unwrap();
cmd.current_dir("tests/examples");
cmd
}
trait PrettyAssert<S>
where
S: AsRef<str>,
{
fn pretty_stdout(self, other: S);
}
// https://github.com/assert-rs/assert_cmd/issues/121#issuecomment-849937376
//
impl<S> PrettyAssert<S> for assert_cmd::assert::Assert
where
S: AsRef<str>,
{
fn pretty_stdout(self, other: S) {
println!("{}", other.as_ref().len());
let self_str = String::from_utf8(self.get_output().stdout.clone()).unwrap();
println!("{}", self_str.len());
pretty_assertions::assert_eq!(self_str, other.as_ref());
}
}
mod basic {
use super::hexyl;
@@ -51,7 +71,7 @@ mod basic {
.success()
.stdout(
"┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐\n\
│ │ No content to print │ │ │ │\n\
│ │ No content │ │ │ │\n\
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘\n",
);
}
@@ -70,8 +90,8 @@ mod length {
.success()
.stdout(
"┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐\n\
│00000000│ 7f 45 4c 46 02 01 01 00 ┊ 00 00 00 00 00 00 00 00 │•ELF•••0┊00000000│\n\
│00000010│ 02 00 3e 00 01 00 00 00 ┊ 00 10 40 00 00 00 00 00 │•0>0•000┊0•@00000│\n\
│00000000│ 7f 45 4c 46 02 01 01 00 ┊ 00 00 00 00 00 00 00 00 │•ELF•••⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│\n\
│00000010│ 02 00 3e 00 01 00 00 00 ┊ 00 10 40 00 00 00 00 00 │•⋄>⋄•⋄⋄⋄┊⋄•@⋄⋄⋄⋄⋄│\n\
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘\n",
);
}
@@ -140,7 +160,7 @@ mod skip {
.success()
.stdout(
"┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐\n\
│ │ No content to print │ │ │ │\n\
│ │ No content │ │ │ │\n\
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘\n",
);
}
@@ -203,7 +223,7 @@ mod display_offset {
.success()
.stdout(
"┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐\n\
│00000030│ 02 00 3e 00 01 00 00 00 ┊ 00 10 40 00 00 00 00 00 │•0>0•000┊0•@00000│\n\
│00000030│ 02 00 3e 00 01 00 00 00 ┊ 00 10 40 00 00 00 00 00 │•⋄>⋄•⋄⋄⋄┊⋄•@⋄⋄⋄⋄⋄│\n\
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘\n",
);
}
@@ -271,3 +291,281 @@ mod display_settings {
);
}
}
mod group {
use super::hexyl;
use super::PrettyAssert;
#[test]
fn group_2_bytes() {
hexyl()
.arg("ascii")
.arg("--color=never")
.arg("--group-bytes=2")
.assert()
.success()
.stdout(
"┌────────┬─────────────────────┬─────────────────────┬────────┬────────┐\n\
│00000000│ 3031 3233 3435 3637 ┊ 3839 6162 6364 650a │01234567┊89abcde_│\n\
└────────┴─────────────────────┴─────────────────────┴────────┴────────┘\n",
);
}
#[test]
fn group_4_bytes() {
hexyl()
.arg("ascii")
.arg("--color=never")
.arg("--group-bytes=4")
.assert()
.success()
.stdout(
"┌────────┬───────────────────┬───────────────────┬────────┬────────┐\n\
│00000000│ 30313233 34353637 ┊ 38396162 6364650a │01234567┊89abcde_│\n\
└────────┴───────────────────┴───────────────────┴────────┴────────┘\n",
);
}
#[test]
fn group_8_bytes() {
hexyl()
.arg("ascii")
.arg("--color=never")
.arg("--group-bytes=8")
.assert()
.success()
.stdout(
"┌────────┬──────────────────┬──────────────────┬────────┬────────┐\n\
│00000000│ 3031323334353637 ┊ 383961626364650a │01234567┊89abcde_│\n\
└────────┴──────────────────┴──────────────────┴────────┴────────┘\n",
);
}
#[test]
fn group_bytes_plain() {
hexyl()
.arg("ascii")
.arg("--color=never")
.arg("--plain")
.arg("--group-bytes=2")
.assert()
.success()
.stdout(" 3031 3233 3435 3637 3839 6162 6364 650a \n");
}
#[test]
fn group_bytes_fill_space() {
hexyl()
.arg("--color=never")
.arg("--group-bytes=2")
.write_stdin("abc")
.assert()
.success()
.stdout(
"┌────────┬─────────────────────┬─────────────────────┬────────┬────────┐\n\
│00000000│ 6162 63 ┊ │abc ┊ │\n\
└────────┴─────────────────────┴─────────────────────┴────────┴────────┘\n",
);
}
#[test]
fn group_bytes_invalid() {
hexyl()
.arg("ascii")
.arg("--color=never")
.arg("--plain")
.arg("--group-bytes=3")
.assert()
.failure();
}
#[test]
fn squeeze_no_chars() {
hexyl()
.arg("hello_world_elf64")
.arg("--color=never")
.arg("--skip=1024")
.arg("--length=4096")
.arg("--no-characters")
.assert()
.success()
.pretty_stdout(
"\
┌────────┬─────────────────────────┬─────────────────────────┐
│00000400│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │
│* │ ┊ │
│00001000│ ba 0e 00 00 00 b9 00 20 ┊ 40 00 bb 01 00 00 00 b8 │
│00001010│ 04 00 00 00 cd 80 b8 01 ┊ 00 00 00 cd 80 00 00 00 │
│00001020│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │
│* │ ┊ │
│00001400│ ┊ │
└────────┴─────────────────────────┴─────────────────────────┘
",
);
}
#[test]
fn squeeze_no_chars_one_panel() {
hexyl()
.arg("hello_world_elf64")
.arg("--color=never")
.arg("--skip=1024")
.arg("--length=4096")
.arg("--no-characters")
.arg("--panels=1")
.assert()
.success()
.pretty_stdout(
"\
┌────────┬─────────────────────────┐
│00000400│ 00 00 00 00 00 00 00 00 │
│* │ │
│00001000│ ba 0e 00 00 00 b9 00 20 │
│00001008│ 40 00 bb 01 00 00 00 b8 │
│00001010│ 04 00 00 00 cd 80 b8 01 │
│00001018│ 00 00 00 cd 80 00 00 00 │
│00001020│ 00 00 00 00 00 00 00 00 │
│* │ │
│00001400│ │
└────────┴─────────────────────────┘
",
);
}
#[test]
fn squeeze_no_position() {
hexyl()
.arg("hello_world_elf64")
.arg("--color=never")
.arg("--skip=1024")
.arg("--length=4096")
.arg("--no-position")
.assert()
.success()
.pretty_stdout(
"\
┌─────────────────────────┬─────────────────────────┬────────┬────────┐
│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│* ┊ │ ┊ │
│ ba 0e 00 00 00 b9 00 20 ┊ 40 00 bb 01 00 00 00 b8 │ו⋄⋄⋄×⋄ ┊@⋄ו⋄⋄⋄×│
│ 04 00 00 00 cd 80 b8 01 ┊ 00 00 00 cd 80 00 00 00 │•⋄⋄⋄××ו┊⋄⋄⋄××⋄⋄⋄│
│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│* ┊ │ ┊ │
│* ┊ │ ┊ │
└─────────────────────────┴─────────────────────────┴────────┴────────┘
",
);
}
#[test]
fn squeeze_no_position_one_panel() {
hexyl()
.arg("hello_world_elf64")
.arg("--color=never")
.arg("--skip=1024")
.arg("--length=4096")
.arg("--no-position")
.arg("--panels=1")
.assert()
.success()
.pretty_stdout(
"\
┌─────────────────────────┬────────┐
│ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄│
│* │ │
│ ba 0e 00 00 00 b9 00 20 │ו⋄⋄⋄×⋄ │
│ 40 00 bb 01 00 00 00 b8 │@⋄ו⋄⋄⋄×│
│ 04 00 00 00 cd 80 b8 01 │•⋄⋄⋄××ו│
│ 00 00 00 cd 80 00 00 00 │⋄⋄⋄××⋄⋄⋄│
│ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄│
│* │ │
│* │ │
└─────────────────────────┴────────┘
",
);
}
#[test]
fn squeeze_odd_panels_remainder_bytes() {
hexyl()
.arg("hello_world_elf64")
.arg("--color=never")
.arg("--skip=1024")
.arg("--length=4092") // 4 byte remainder
.arg("--panels=3")
.assert()
.success()
.pretty_stdout(
"\
┌────────┬─────────────────────────┬─────────────────────────┬─────────────────────────┬────────┬────────┬────────┐
│00000400│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│* │ ┊ ┊ │ ┊ ┊ │
│00001000│ ba 0e 00 00 00 b9 00 20 ┊ 40 00 bb 01 00 00 00 b8 ┊ 04 00 00 00 cd 80 b8 01 │ו⋄⋄⋄×⋄ ┊@⋄ו⋄⋄⋄×┊•⋄⋄⋄××ו│
│00001018│ 00 00 00 cd 80 00 00 00 ┊ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄××⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│00001030│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│* │ ┊ ┊ │ ┊ ┊ │
│000013f0│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 ┊ │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄ ┊ │
└────────┴─────────────────────────┴─────────────────────────┴─────────────────────────┴────────┴────────┴────────┘
",
);
}
#[test]
fn squeeze_plain() {
hexyl()
.arg("hello_world_elf64")
.arg("--color=never")
.arg("--skip=1024")
.arg("--length=4096")
.arg("--plain")
.assert()
.success()
.pretty_stdout(
" \
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
*
ba 0e 00 00 00 b9 00 20 40 00 bb 01 00 00 00 b8
04 00 00 00 cd 80 b8 01 00 00 00 cd 80 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
*
*
",
);
}
#[test]
fn squeeze_plain_remainder() {
hexyl()
.arg("hello_world_elf64")
.arg("--color=never")
.arg("--skip=1024")
.arg("--length=4092") // 4 byte remainder
.arg("--plain")
.assert()
.success()
.pretty_stdout(
" \
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
*
ba 0e 00 00 00 b9 00 20 40 00 bb 01 00 00 00 b8
04 00 00 00 cd 80 b8 01 00 00 00 cd 80 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
*
00 00 00 00 00 00 00 00 00 00 00 00
",
);
}
}
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"
);
}
}