mirror of
https://github.com/sharkdp/hexyl.git
synced 2026-10-30 09:05:54 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
692ff64e4b | ||
|
|
1d156282da | ||
|
|
b4bdf0f85e | ||
|
|
2bda250906 | ||
|
|
f32431e552 | ||
|
|
f9cb2bc872 | ||
|
|
f71ad1e00d | ||
|
|
3b01d0ce19 | ||
|
|
abc79396df | ||
|
|
67b6c2533d | ||
|
|
c75a882081 | ||
|
|
81787d0858 | ||
|
|
8e77507686 | ||
|
|
9c46ced572 | ||
|
|
161ddd7ea1 | ||
|
|
53110bac6f | ||
|
|
d64053771c | ||
|
|
23f199ffbd | ||
|
|
175847787d | ||
|
|
622a084ea6 | ||
|
|
4c48eedb18 | ||
|
|
ca8970b5cc | ||
|
|
fb49b633b2 | ||
|
|
82c34fe39b | ||
|
|
c4028bb213 | ||
|
|
def066ff92 | ||
|
|
17c2c61bad | ||
|
|
2ad15413b9 | ||
|
|
710c86f6a1 | ||
|
|
a2ea80e960 | ||
|
|
3390bedee9 | ||
|
|
6978f7a277 | ||
|
|
2c7c857ccc | ||
|
|
55adb2db2c | ||
|
|
3a62809c8c | ||
|
|
7cc0b51537 | ||
|
|
8363e3f37e | ||
|
|
07c222947d | ||
|
|
2566d7b9f9 | ||
|
|
8bd7677c9b | ||
|
|
6a848b14f8 | ||
|
|
c6c4dd416e | ||
|
|
f918bfb911 | ||
|
|
10e3535999 | ||
|
|
8725f8cd25 | ||
|
|
c8e65d7528 | ||
|
|
170573fad0 | ||
|
|
880807619f | ||
|
|
7e46a5d788 | ||
|
|
19030470f9 | ||
|
|
b27ab61608 | ||
|
|
39a83021dc | ||
|
|
f6f41e76aa | ||
|
|
74861353fa | ||
|
|
78d8cc516f | ||
|
|
faebee7b8c | ||
|
|
92c974d066 | ||
|
|
866feb2966 | ||
|
|
952fff0ee4 | ||
|
|
1619cd5afe | ||
|
|
20694bb628 | ||
|
|
98311282e5 | ||
|
|
afb6669477 | ||
|
|
0dad8bf481 | ||
|
|
612a227a81 | ||
|
|
351fcf0aea | ||
|
|
3c3d91cd51 | ||
|
|
7b7a0ff32d | ||
|
|
2e403a2d11 | ||
|
|
155b14e865 | ||
|
|
8429b87594 | ||
|
|
1cddf395a8 | ||
|
|
2a1ae1d295 | ||
|
|
57e1c67bfb |
No files matched your search
@@ -0,0 +1 @@
|
|||||||
|
github: sharkdp
|
||||||
+4
-4
@@ -14,11 +14,11 @@ matrix:
|
|||||||
env: TARGET=x86_64-apple-darwin
|
env: TARGET=x86_64-apple-darwin
|
||||||
- os: windows
|
- os: windows
|
||||||
rust: stable
|
rust: stable
|
||||||
env: TARGET=x86_64-pc-windows-msvc
|
env: TARGET=x86_64-pc-windows-gnu
|
||||||
|
|
||||||
# Minimum Rust supported channel.
|
# Minimum Rust supported channel.
|
||||||
- os: linux
|
- os: linux
|
||||||
rust: 1.29.0
|
rust: 1.31.0
|
||||||
env: TARGET=x86_64-unknown-linux-gnu
|
env: TARGET=x86_64-unknown-linux-gnu
|
||||||
|
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ install:
|
|||||||
script:
|
script:
|
||||||
# Incorporate TARGET env var to the build and test process
|
# Incorporate TARGET env var to the build and test process
|
||||||
- cargo build --target $TARGET --verbose
|
- cargo build --target $TARGET --verbose
|
||||||
#- cargo test --target $TARGET --verbose
|
- cargo test --target $TARGET --verbose
|
||||||
|
|
||||||
before_deploy:
|
before_deploy:
|
||||||
- bash ci/before_deploy.bash
|
- bash ci/before_deploy.bash
|
||||||
@@ -72,7 +72,7 @@ deploy:
|
|||||||
# deploy only if we push a tag
|
# deploy only if we push a tag
|
||||||
tags: true
|
tags: true
|
||||||
# deploy only on stable channel that has TARGET env variable sets
|
# deploy only on stable channel that has TARGET env variable sets
|
||||||
condition: $TRAVIS_RUST_VERSION = stable && $TARGET != ""
|
condition: $TRAVIS_RUST_VERSION = stable && $TARGET != "x86_64-pc-windows-gnu"
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email:
|
email:
|
||||||
|
|||||||
Generated
+52
-57
@@ -1,47 +1,66 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ansi_term"
|
name = "ansi_term"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ansi_term"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.11"
|
version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.0.4"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "2.32.0"
|
version = "2.33.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hexyl"
|
name = "hermit-abi"
|
||||||
version = "0.3.0"
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hexyl"
|
||||||
|
version = "0.7.0"
|
||||||
|
dependencies = [
|
||||||
|
"ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -55,25 +74,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.45"
|
version = "0.2.67"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "redox_syscall"
|
|
||||||
version = "0.1.49"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "redox_termios"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"redox_syscall 0.1.49 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.7.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -82,32 +88,22 @@ version = "0.3.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "termion"
|
|
||||||
version = "1.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"redox_syscall 0.1.49 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.10.0"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
version = "0.1.5"
|
version = "0.1.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -122,7 +118,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.6"
|
version = "0.3.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -146,21 +142,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||||
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
"checksum ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||||
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
|
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||||
|
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
||||||
|
"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8"
|
||||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||||
"checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74"
|
"checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018"
|
||||||
"checksum redox_syscall 0.1.49 (registry+https://github.com/rust-lang/crates.io-index)" = "f22c50afdcf3f0a31ebb6b47697f6a7c5e5a24967e842858118bce0615f0afad"
|
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
|
||||||
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
|
|
||||||
"checksum term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327"
|
"checksum term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327"
|
||||||
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
|
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||||
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
|
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
||||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
|
||||||
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
+8
-2
@@ -7,11 +7,17 @@ license = "MIT/Apache-2.0"
|
|||||||
name = "hexyl"
|
name = "hexyl"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://github.com/sharkdp/hexyl"
|
repository = "https://github.com/sharkdp/hexyl"
|
||||||
version = "0.3.0"
|
version = "0.7.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ansi_term = "0.11"
|
ansi_term = "0.12"
|
||||||
|
atty = "0.2"
|
||||||
|
|
||||||
[dependencies.clap]
|
[dependencies.clap]
|
||||||
version = "2"
|
version = "2"
|
||||||
features = ["suggestions", "color", "wrap_help"]
|
features = ["suggestions", "color", "wrap_help"]
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
||||||
|
codegen-units = 1
|
||||||
@@ -19,29 +19,70 @@ of bytes (NULL bytes, printable ASCII characters, ASCII whitespace characters, o
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### On Debian-based systems
|
### On Ubuntu
|
||||||
|
|
||||||
|
*... and other Debian-based Linux distributions.*
|
||||||
|
|
||||||
|
If you run Ubuntu 19.10 (Eoan Ermine) or newer, you can install the [officially maintained package](https://packages.ubuntu.com/eoan/hexyl):
|
||||||
|
```bash
|
||||||
|
sudo apt install hexyl
|
||||||
|
```
|
||||||
|
If you use an older version of Ubuntu, you can download
|
||||||
|
the latest `.deb` package from the release page and install it via:
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
wget "https://github.com/sharkdp/hexyl/releases/download/v0.3.0/hexyl_0.3.0_amd64.deb"
|
sudo dpkg -i hexyl_0.7.0_amd64.deb # adapt version number and architecture
|
||||||
sudo dpkg -i hexyl_0.3.0_amd64.deb
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### On Debian
|
||||||
|
|
||||||
|
If you run Debian Buster or newer, you can install the [officially maintained Debian package](https://packages.debian.org/buster/hexyl):
|
||||||
|
```bash
|
||||||
|
sudo apt-get install hexyl
|
||||||
|
```
|
||||||
|
|
||||||
|
If you run an older version of Debian, see above for instructions on how to
|
||||||
|
manually install `hexyl`.
|
||||||
|
|
||||||
### On Arch Linux
|
### On Arch Linux
|
||||||
|
|
||||||
You can install `hexyl` from [this AUR package](https://aur.archlinux.org/packages/hexyl/):
|
You can install `hexyl` from [the official package repository](https://www.archlinux.org/packages/community/x86_64/hexyl/):
|
||||||
|
|
||||||
```
|
```
|
||||||
yaourt -S hexyl
|
pacman -S hexyl
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### On macOS
|
||||||
|
|
||||||
|
```
|
||||||
|
brew install hexyl
|
||||||
|
```
|
||||||
|
|
||||||
|
### On FreeBSD
|
||||||
|
|
||||||
|
```
|
||||||
|
pkg install hexyl
|
||||||
|
```
|
||||||
|
|
||||||
|
### Via Nix
|
||||||
|
|
||||||
|
```
|
||||||
|
nix-env -i hexyl
|
||||||
|
```
|
||||||
|
|
||||||
### On other distributions
|
### On other distributions
|
||||||
|
|
||||||
Check out the [release page](https://github.com/sharkdp/hexyl/releases) for binary builds.
|
Check out the [release page](https://github.com/sharkdp/hexyl/releases) for binary builds.
|
||||||
|
|
||||||
|
### On Windows
|
||||||
|
|
||||||
|
For now, you will have to install from source via `cargo` (see below). Make sure that you
|
||||||
|
use a terminal that supports ANSI escape sequences (like ConHost v2 since Windows 10 1703
|
||||||
|
or Windows Terminal since Windows 10 1903).
|
||||||
|
|
||||||
### Via cargo
|
### Via cargo
|
||||||
|
|
||||||
If you have Rust 1.29 or higher, you can install `hexyl` from source via `cargo`:
|
If you have Rust 1.31 or higher, you can install `hexyl` from source via `cargo`:
|
||||||
```
|
```
|
||||||
cargo install hexyl
|
cargo install hexyl
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
use std::io;
|
||||||
|
|
||||||
|
use hexyl::{BorderStyle, Printer};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let input = vec![
|
||||||
|
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44,
|
||||||
|
0x52, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x44, 0x08, 0x02, 0x00, 0x00, 0x00,
|
||||||
|
];
|
||||||
|
|
||||||
|
let stdout = io::stdout();
|
||||||
|
let mut handle = stdout.lock();
|
||||||
|
|
||||||
|
let show_color = true;
|
||||||
|
let use_squeezing = false;
|
||||||
|
let border_style = BorderStyle::Unicode;
|
||||||
|
|
||||||
|
let mut printer = Printer::new(&mut handle, show_color, border_style, use_squeezing);
|
||||||
|
printer.print_all(&input[..]).unwrap();
|
||||||
|
}
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
#[macro_use]
|
||||||
|
extern crate clap;
|
||||||
|
|
||||||
|
use atty;
|
||||||
|
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{self, prelude::*};
|
||||||
|
|
||||||
|
use clap::{App, AppSettings, Arg};
|
||||||
|
|
||||||
|
use atty::Stream;
|
||||||
|
|
||||||
|
use hexyl::{BorderStyle, Printer};
|
||||||
|
|
||||||
|
fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let app = App::new(crate_name!())
|
||||||
|
.setting(AppSettings::ColorAuto)
|
||||||
|
.setting(AppSettings::ColoredHelp)
|
||||||
|
.setting(AppSettings::DeriveDisplayOrder)
|
||||||
|
.setting(AppSettings::UnifiedHelpMessage)
|
||||||
|
.version(crate_version!())
|
||||||
|
.about(crate_description!())
|
||||||
|
.arg(Arg::with_name("file").help("File to display"))
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("length")
|
||||||
|
.short("n")
|
||||||
|
.long("length")
|
||||||
|
.takes_value(true)
|
||||||
|
.value_name("N")
|
||||||
|
.help("Read only N bytes from the input"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("bytes")
|
||||||
|
.short("c")
|
||||||
|
.long("bytes")
|
||||||
|
.takes_value(true)
|
||||||
|
.value_name("N")
|
||||||
|
.help("An alias for -n/--length"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("nosqueezing")
|
||||||
|
.short("v")
|
||||||
|
.long("no-squeezing")
|
||||||
|
.help(
|
||||||
|
"Displays all input data. Otherwise any number of groups of output \
|
||||||
|
lines which would be identical to the preceding group of lines, are \
|
||||||
|
replaced with a line comprised of a single asterisk.",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("color")
|
||||||
|
.long("color")
|
||||||
|
.takes_value(true)
|
||||||
|
.value_name("when")
|
||||||
|
.possible_values(&["always", "auto", "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::with_name("border")
|
||||||
|
.long("border")
|
||||||
|
.takes_value(true)
|
||||||
|
.possible_values(&["unicode", "ascii", "none"])
|
||||||
|
.default_value("unicode")
|
||||||
|
.help("Whether to draw a border with unicode or ASCII characters, or none at all"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("display_offset")
|
||||||
|
.short("o")
|
||||||
|
.long("display-offset")
|
||||||
|
.takes_value(true)
|
||||||
|
.value_name("OFFSET")
|
||||||
|
.help("Add OFFSET to the displayed file position."),
|
||||||
|
);
|
||||||
|
|
||||||
|
let matches = app.get_matches_safe()?;
|
||||||
|
|
||||||
|
let stdin = io::stdin();
|
||||||
|
|
||||||
|
let mut reader: Box<dyn Read> = match matches.value_of("file") {
|
||||||
|
Some(filename) => Box::new(File::open(filename)?),
|
||||||
|
None => Box::new(stdin.lock()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let length_arg = matches.value_of("length").or(matches.value_of("bytes"));
|
||||||
|
|
||||||
|
if let Some(length) = length_arg.and_then(parse_hex_or_int) {
|
||||||
|
reader = Box::new(reader.take(length));
|
||||||
|
}
|
||||||
|
|
||||||
|
let show_color = match matches.value_of("color") {
|
||||||
|
Some("never") => false,
|
||||||
|
Some("auto") => atty::is(Stream::Stdout),
|
||||||
|
_ => true,
|
||||||
|
};
|
||||||
|
|
||||||
|
let border_style = match matches.value_of("border") {
|
||||||
|
Some("unicode") => BorderStyle::Unicode,
|
||||||
|
Some("ascii") => BorderStyle::Ascii,
|
||||||
|
_ => BorderStyle::None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let squeeze = !matches.is_present("nosqueezing");
|
||||||
|
|
||||||
|
let display_offset = matches
|
||||||
|
.value_of("display_offset")
|
||||||
|
.and_then(parse_hex_or_int)
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
let stdout = io::stdout();
|
||||||
|
let mut stdout_lock = stdout.lock();
|
||||||
|
|
||||||
|
let mut printer = Printer::new(&mut stdout_lock, show_color, border_style, squeeze);
|
||||||
|
printer.display_offset(display_offset as usize);
|
||||||
|
printer.print_all(&mut reader)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
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(clap_err) = err.downcast_ref::<clap::Error>() {
|
||||||
|
eprint!("{}", clap_err); // Clap errors already have newlines
|
||||||
|
|
||||||
|
match clap_err.kind {
|
||||||
|
// The exit code should not indicate an error for --help / --version
|
||||||
|
clap::ErrorKind::HelpDisplayed | clap::ErrorKind::VersionDisplayed => {
|
||||||
|
std::process::exit(0)
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eprintln!("Error: {}", err);
|
||||||
|
}
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_hex_or_int(n: &str) -> Option<u64> {
|
||||||
|
if n.starts_with("0x") {
|
||||||
|
u64::from_str_radix(n.trim_start_matches("0x"), 16).ok()
|
||||||
|
} else {
|
||||||
|
n.parse::<u64>().ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
+501
@@ -0,0 +1,501 @@
|
|||||||
|
pub mod squeezer;
|
||||||
|
|
||||||
|
use std::io::{self, Read, Write};
|
||||||
|
|
||||||
|
use ansi_term::Color;
|
||||||
|
use ansi_term::Color::Fixed;
|
||||||
|
|
||||||
|
use crate::squeezer::{SqueezeAction, Squeezer};
|
||||||
|
|
||||||
|
const BUFFER_SIZE: usize = 256;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
pub enum ByteCategory {
|
||||||
|
Null,
|
||||||
|
AsciiPrintable,
|
||||||
|
AsciiWhitespace,
|
||||||
|
AsciiOther,
|
||||||
|
NonAscii,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
struct Byte(u8);
|
||||||
|
|
||||||
|
impl Byte {
|
||||||
|
fn category(self) -> ByteCategory {
|
||||||
|
if self.0 == 0x00 {
|
||||||
|
ByteCategory::Null
|
||||||
|
} else if self.0.is_ascii_alphanumeric()
|
||||||
|
|| self.0.is_ascii_punctuation()
|
||||||
|
|| self.0.is_ascii_graphic()
|
||||||
|
{
|
||||||
|
ByteCategory::AsciiPrintable
|
||||||
|
} else if self.0.is_ascii_whitespace() {
|
||||||
|
ByteCategory::AsciiWhitespace
|
||||||
|
} else if self.0.is_ascii() {
|
||||||
|
ByteCategory::AsciiOther
|
||||||
|
} else {
|
||||||
|
ByteCategory::NonAscii
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn color(self) -> &'static Color {
|
||||||
|
use crate::ByteCategory::*;
|
||||||
|
|
||||||
|
match self.category() {
|
||||||
|
Null => &COLOR_NULL,
|
||||||
|
AsciiPrintable => &COLOR_ASCII_PRINTABLE,
|
||||||
|
AsciiWhitespace => &COLOR_ASCII_WHITESPACE,
|
||||||
|
AsciiOther => &COLOR_ASCII_OTHER,
|
||||||
|
NonAscii => &COLOR_NONASCII,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_char(self) -> char {
|
||||||
|
use crate::ByteCategory::*;
|
||||||
|
|
||||||
|
match self.category() {
|
||||||
|
Null => '0',
|
||||||
|
AsciiPrintable => self.0 as char,
|
||||||
|
AsciiWhitespace if self.0 == 0x20 => ' ',
|
||||||
|
AsciiWhitespace => '_',
|
||||||
|
AsciiOther => '•',
|
||||||
|
NonAscii => '×',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BorderElements {
|
||||||
|
left_corner: char,
|
||||||
|
horizontal_line: char,
|
||||||
|
column_separator: char,
|
||||||
|
right_corner: char,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum BorderStyle {
|
||||||
|
Unicode,
|
||||||
|
Ascii,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BorderStyle {
|
||||||
|
fn header_elems(&self) -> Option<BorderElements> {
|
||||||
|
match self {
|
||||||
|
BorderStyle::Unicode => Some(BorderElements {
|
||||||
|
left_corner: '┌',
|
||||||
|
horizontal_line: '─',
|
||||||
|
column_separator: '┬',
|
||||||
|
right_corner: '┐',
|
||||||
|
}),
|
||||||
|
BorderStyle::Ascii => Some(BorderElements {
|
||||||
|
left_corner: '+',
|
||||||
|
horizontal_line: '-',
|
||||||
|
column_separator: '+',
|
||||||
|
right_corner: '+',
|
||||||
|
}),
|
||||||
|
BorderStyle::None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn footer_elems(&self) -> Option<BorderElements> {
|
||||||
|
match self {
|
||||||
|
BorderStyle::Unicode => Some(BorderElements {
|
||||||
|
left_corner: '└',
|
||||||
|
horizontal_line: '─',
|
||||||
|
column_separator: '┴',
|
||||||
|
right_corner: '┘',
|
||||||
|
}),
|
||||||
|
BorderStyle::Ascii => Some(BorderElements {
|
||||||
|
left_corner: '+',
|
||||||
|
horizontal_line: '-',
|
||||||
|
column_separator: '+',
|
||||||
|
right_corner: '+',
|
||||||
|
}),
|
||||||
|
BorderStyle::None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn outer_sep(&self) -> char {
|
||||||
|
match self {
|
||||||
|
BorderStyle::Unicode => '│',
|
||||||
|
BorderStyle::Ascii => '|',
|
||||||
|
BorderStyle::None => ' ',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inner_sep(&self) -> char {
|
||||||
|
match self {
|
||||||
|
BorderStyle::Unicode => '┊',
|
||||||
|
BorderStyle::Ascii => '|',
|
||||||
|
BorderStyle::None => ' ',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Printer<'a, Writer: Write> {
|
||||||
|
idx: usize,
|
||||||
|
/// 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>,
|
||||||
|
writer: &'a mut Writer,
|
||||||
|
show_color: bool,
|
||||||
|
border_style: BorderStyle,
|
||||||
|
header_was_printed: bool,
|
||||||
|
byte_hex_table: Vec<String>,
|
||||||
|
byte_char_table: Vec<String>,
|
||||||
|
squeezer: Squeezer,
|
||||||
|
display_offset: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Writer: Write> Printer<'a, Writer> {
|
||||||
|
pub fn new(
|
||||||
|
writer: &'a mut Writer,
|
||||||
|
show_color: bool,
|
||||||
|
border_style: BorderStyle,
|
||||||
|
use_squeeze: bool,
|
||||||
|
) -> Printer<'a, Writer> {
|
||||||
|
Printer {
|
||||||
|
idx: 1,
|
||||||
|
raw_line: vec![],
|
||||||
|
buffer_line: vec![],
|
||||||
|
writer,
|
||||||
|
show_color,
|
||||||
|
border_style,
|
||||||
|
header_was_printed: false,
|
||||||
|
byte_hex_table: (0u8..=u8::max_value())
|
||||||
|
.map(|i| {
|
||||||
|
let byte_hex = format!("{:02x} ", i);
|
||||||
|
if show_color {
|
||||||
|
Byte(i).color().paint(byte_hex).to_string()
|
||||||
|
} else {
|
||||||
|
byte_hex
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
byte_char_table: (0u8..=u8::max_value())
|
||||||
|
.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(),
|
||||||
|
squeezer: Squeezer::new(use_squeeze),
|
||||||
|
display_offset: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn display_offset(&mut self, display_offset: usize) -> &mut Self {
|
||||||
|
self.display_offset = display_offset;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn header(&mut self) {
|
||||||
|
if let Some(border_elements) = self.border_style.header_elems() {
|
||||||
|
let h = border_elements.horizontal_line;
|
||||||
|
let h8 = h.to_string().repeat(8);
|
||||||
|
let h25 = h.to_string().repeat(25);
|
||||||
|
|
||||||
|
writeln!(
|
||||||
|
self.writer,
|
||||||
|
"{l}{h8}{c}{h25}{c}{h25}{c}{h8}{c}{h8}{r}",
|
||||||
|
l = border_elements.left_corner,
|
||||||
|
c = border_elements.column_separator,
|
||||||
|
r = border_elements.right_corner,
|
||||||
|
h8 = h8,
|
||||||
|
h25 = h25
|
||||||
|
)
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn footer(&mut self) {
|
||||||
|
if let Some(border_elements) = self.border_style.footer_elems() {
|
||||||
|
let h = border_elements.horizontal_line;
|
||||||
|
let h8 = h.to_string().repeat(8);
|
||||||
|
let h25 = h.to_string().repeat(25);
|
||||||
|
|
||||||
|
writeln!(
|
||||||
|
self.writer,
|
||||||
|
"{l}{h8}{c}{h25}{c}{h25}{c}{h8}{c}{h8}{r}",
|
||||||
|
l = border_elements.left_corner,
|
||||||
|
c = border_elements.column_separator,
|
||||||
|
r = border_elements.right_corner,
|
||||||
|
h8 = h8,
|
||||||
|
h25 = h25
|
||||||
|
)
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_position_indicator(&mut self) {
|
||||||
|
if !self.header_was_printed {
|
||||||
|
self.header();
|
||||||
|
self.header_was_printed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_byte(&mut self, b: u8) -> io::Result<()> {
|
||||||
|
if self.idx % 16 == 1 {
|
||||||
|
self.print_position_indicator();
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(&mut self.buffer_line, "{}", self.byte_hex_table[b as usize])?;
|
||||||
|
self.raw_line.push(b);
|
||||||
|
|
||||||
|
self.squeezer.process(b, self.idx);
|
||||||
|
|
||||||
|
match self.idx % 16 {
|
||||||
|
8 => {
|
||||||
|
let _ = write!(&mut self.buffer_line, "{} ", self.border_style.inner_sep());
|
||||||
|
}
|
||||||
|
0 => {
|
||||||
|
self.print_textline()?;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
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_indicator();
|
||||||
|
let _ = writeln!(
|
||||||
|
&mut self.buffer_line,
|
||||||
|
"{0:1$}{4}{0:2$}{5}{0:3$}{4}{0:3$}{5}",
|
||||||
|
"",
|
||||||
|
24,
|
||||||
|
25,
|
||||||
|
8,
|
||||||
|
self.border_style.inner_sep(),
|
||||||
|
self.border_style.outer_sep(),
|
||||||
|
);
|
||||||
|
self.writer.write_all(&self.buffer_line)?;
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
let squeeze_action = self.squeezer.action();
|
||||||
|
|
||||||
|
if squeeze_action != SqueezeAction::Delete {
|
||||||
|
if len < 8 {
|
||||||
|
let _ = write!(
|
||||||
|
&mut self.buffer_line,
|
||||||
|
"{0:1$}{3}{0:2$}{4}",
|
||||||
|
"",
|
||||||
|
3 * (8 - len),
|
||||||
|
1 + 3 * 8,
|
||||||
|
self.border_style.inner_sep(),
|
||||||
|
self.border_style.outer_sep(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let _ = write!(
|
||||||
|
&mut self.buffer_line,
|
||||||
|
"{0:1$}{2}",
|
||||||
|
"",
|
||||||
|
3 * (16 - len),
|
||||||
|
self.border_style.outer_sep()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut idx = 1;
|
||||||
|
for &b in self.raw_line.iter() {
|
||||||
|
let _ = write!(
|
||||||
|
&mut self.buffer_line,
|
||||||
|
"{}",
|
||||||
|
self.byte_char_table[b as usize]
|
||||||
|
);
|
||||||
|
|
||||||
|
if idx == 8 {
|
||||||
|
let _ = write!(&mut self.buffer_line, "{}", self.border_style.inner_sep());
|
||||||
|
}
|
||||||
|
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if len < 8 {
|
||||||
|
let _ = writeln!(
|
||||||
|
&mut self.buffer_line,
|
||||||
|
"{0:1$}{3}{0:2$}{4}",
|
||||||
|
"",
|
||||||
|
8 - len,
|
||||||
|
8,
|
||||||
|
self.border_style.inner_sep(),
|
||||||
|
self.border_style.outer_sep(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let _ = writeln!(
|
||||||
|
&mut self.buffer_line,
|
||||||
|
"{0:1$}{2}",
|
||||||
|
"",
|
||||||
|
16 - len,
|
||||||
|
self.border_style.outer_sep()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
match squeeze_action {
|
||||||
|
SqueezeAction::Print => {
|
||||||
|
self.buffer_line.clear();
|
||||||
|
let style = COLOR_OFFSET.normal();
|
||||||
|
let asterisk = if self.show_color {
|
||||||
|
format!("{}", style.paint("*"))
|
||||||
|
} else {
|
||||||
|
String::from("*")
|
||||||
|
};
|
||||||
|
let _ = writeln!(
|
||||||
|
&mut self.buffer_line,
|
||||||
|
"{5}{0}{1:2$}{5}{1:3$}{6}{1:3$}{5}{1:4$}{6}{1:4$}{5}",
|
||||||
|
asterisk,
|
||||||
|
"",
|
||||||
|
7,
|
||||||
|
25,
|
||||||
|
8,
|
||||||
|
self.border_style.outer_sep(),
|
||||||
|
self.border_style.inner_sep(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
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();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn header_was_printed(&self) -> bool {
|
||||||
|
self.header_was_printed
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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>> {
|
||||||
|
let mut buffer = [0; BUFFER_SIZE];
|
||||||
|
'mainloop: loop {
|
||||||
|
let size = reader.read(&mut buffer)?;
|
||||||
|
if size == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for b in &buffer[..size] {
|
||||||
|
let res = self.print_byte(*b);
|
||||||
|
|
||||||
|
if res.is_err() {
|
||||||
|
// Broken pipe
|
||||||
|
break 'mainloop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finish last line
|
||||||
|
self.print_textline().ok();
|
||||||
|
if !self.header_was_printed() {
|
||||||
|
self.header();
|
||||||
|
}
|
||||||
|
self.footer();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::io;
|
||||||
|
use std::str;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn assert_print_all_output<Reader: Read>(input: Reader, expected_string: String) -> () {
|
||||||
|
let mut output = vec![];
|
||||||
|
let mut printer = Printer::new(&mut output, false, BorderStyle::Unicode, true);
|
||||||
|
|
||||||
|
printer.print_all(input).unwrap();
|
||||||
|
|
||||||
|
let actual_string: &str = str::from_utf8(&output).unwrap();
|
||||||
|
assert_eq!(actual_string, expected_string)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty_file_passes() {
|
||||||
|
let input = io::empty();
|
||||||
|
let expected_string =
|
||||||
|
"┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
|
||||||
|
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘
|
||||||
|
"
|
||||||
|
.to_owned();
|
||||||
|
assert_print_all_output(input, expected_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn short_input_passes() {
|
||||||
|
let input = io::Cursor::new(b"spam");
|
||||||
|
let expected_string =
|
||||||
|
"┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
|
||||||
|
│00000000│ 73 70 61 6d ┊ │spam ┊ │
|
||||||
|
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘
|
||||||
|
"
|
||||||
|
.to_owned();
|
||||||
|
assert_print_all_output(input, expected_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn display_offset() {
|
||||||
|
let input = io::Cursor::new(b"spamspamspamspamspam");
|
||||||
|
let expected_string =
|
||||||
|
"┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
|
||||||
|
│deadbeef│ 73 70 61 6d 73 70 61 6d ┊ 73 70 61 6d 73 70 61 6d │spamspam┊spamspam│
|
||||||
|
│deadbeff│ 73 70 61 6d ┊ │spam ┊ │
|
||||||
|
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘
|
||||||
|
"
|
||||||
|
.to_owned();
|
||||||
|
|
||||||
|
let mut output = vec![];
|
||||||
|
let mut printer: Printer<Vec<u8>> =
|
||||||
|
Printer::new(&mut output, false, BorderStyle::Unicode, true);
|
||||||
|
printer.display_offset(0xdeadbeef);
|
||||||
|
|
||||||
|
printer.print_all(input).unwrap();
|
||||||
|
|
||||||
|
let actual_string: &str = str::from_utf8(&output).unwrap();
|
||||||
|
assert_eq!(actual_string, expected_string)
|
||||||
|
}
|
||||||
|
}
|
||||||
-261
@@ -1,261 +0,0 @@
|
|||||||
#[macro_use]
|
|
||||||
extern crate clap;
|
|
||||||
extern crate ansi_term;
|
|
||||||
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::{self, prelude::*, StdoutLock};
|
|
||||||
|
|
||||||
use clap::{App, AppSettings, Arg};
|
|
||||||
|
|
||||||
use ansi_term::Colour;
|
|
||||||
use ansi_term::Colour::RGB;
|
|
||||||
|
|
||||||
const BUFFER_SIZE: usize = 64;
|
|
||||||
|
|
||||||
const COLOR_NULL: Colour = RGB(117, 113, 94); // grey
|
|
||||||
const COLOR_OFFSET: Colour = RGB(117, 113, 94); // grey
|
|
||||||
const COLOR_ASCII_PRINTABLE: Colour = RGB(102, 217, 239); // cyan
|
|
||||||
const COLOR_ASCII_WHITESPACE: Colour = RGB(166, 226, 46); // green
|
|
||||||
const COLOR_ASCII_OTHER: Colour = RGB(249, 38, 114); // magenta
|
|
||||||
const COLOR_NONASCII: Colour = RGB(253, 151, 31); // orange
|
|
||||||
|
|
||||||
enum ByteCategory {
|
|
||||||
Null,
|
|
||||||
AsciiPrintable,
|
|
||||||
AsciiWhitespace,
|
|
||||||
AsciiOther,
|
|
||||||
NonAscii,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
struct Byte(u8);
|
|
||||||
|
|
||||||
impl Byte {
|
|
||||||
fn category(self) -> ByteCategory {
|
|
||||||
if self.0 == 0x00 {
|
|
||||||
ByteCategory::Null
|
|
||||||
} else if self.0.is_ascii_alphanumeric()
|
|
||||||
|| self.0.is_ascii_punctuation()
|
|
||||||
|| self.0.is_ascii_graphic()
|
|
||||||
{
|
|
||||||
ByteCategory::AsciiPrintable
|
|
||||||
} else if self.0.is_ascii_whitespace() {
|
|
||||||
ByteCategory::AsciiWhitespace
|
|
||||||
} else if self.0.is_ascii() {
|
|
||||||
ByteCategory::AsciiOther
|
|
||||||
} else {
|
|
||||||
ByteCategory::NonAscii
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn color(self) -> &'static Colour {
|
|
||||||
use ByteCategory::*;
|
|
||||||
|
|
||||||
match self.category() {
|
|
||||||
Null => &COLOR_NULL,
|
|
||||||
AsciiPrintable => &COLOR_ASCII_PRINTABLE,
|
|
||||||
AsciiWhitespace => &COLOR_ASCII_WHITESPACE,
|
|
||||||
AsciiOther => &COLOR_ASCII_OTHER,
|
|
||||||
NonAscii => &COLOR_NONASCII,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_char(self) -> char {
|
|
||||||
use ByteCategory::*;
|
|
||||||
|
|
||||||
match self.category() {
|
|
||||||
Null => '0',
|
|
||||||
AsciiPrintable => self.0 as char,
|
|
||||||
AsciiWhitespace if self.0 == 0x20 => ' ',
|
|
||||||
AsciiWhitespace => '_',
|
|
||||||
AsciiOther => '•',
|
|
||||||
NonAscii => '×',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Printer<'a> {
|
|
||||||
idx: usize,
|
|
||||||
line: Vec<u8>,
|
|
||||||
stdout: StdoutLock<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Printer<'a> {
|
|
||||||
fn new(stdout: StdoutLock) -> Printer {
|
|
||||||
Printer {
|
|
||||||
idx: 1,
|
|
||||||
line: vec![],
|
|
||||||
stdout,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn header(&mut self) {
|
|
||||||
writeln!(
|
|
||||||
self.stdout,
|
|
||||||
"┌{}┬{}┬{}┬{}┬{}┐",
|
|
||||||
"─".repeat(8),
|
|
||||||
"─".repeat(3 * 8 + 1),
|
|
||||||
"─".repeat(3 * 8 + 1),
|
|
||||||
"─".repeat(8),
|
|
||||||
"─".repeat(8)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn footer(&mut self) {
|
|
||||||
writeln!(
|
|
||||||
self.stdout,
|
|
||||||
"└{}┴{}┴{}┴{}┴{}┘",
|
|
||||||
"─".repeat(8),
|
|
||||||
"─".repeat(3 * 8 + 1),
|
|
||||||
"─".repeat(3 * 8 + 1),
|
|
||||||
"─".repeat(8),
|
|
||||||
"─".repeat(8)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_byte(&mut self, b: u8) -> io::Result<()> {
|
|
||||||
if self.idx % 16 == 1 {
|
|
||||||
let offset_str = format!("{:08x}", self.idx - 1);
|
|
||||||
write!(self.stdout, "│{}│ ", COLOR_OFFSET.paint(offset_str))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let byte_str = format!("{:02x} ", b);
|
|
||||||
write!(self.stdout, "{}", Byte(b).color().paint(byte_str))?;
|
|
||||||
self.line.push(b);
|
|
||||||
|
|
||||||
match self.idx % 16 {
|
|
||||||
8 => write!(self.stdout, "┊ ")?,
|
|
||||||
0 => {
|
|
||||||
self.print_textline()?;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.idx += 1;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_textline(&mut self) -> io::Result<()> {
|
|
||||||
let len = self.line.len();
|
|
||||||
|
|
||||||
if len == 0 {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
if len < 8 {
|
|
||||||
write!(
|
|
||||||
self.stdout,
|
|
||||||
"{}┊{}│",
|
|
||||||
" ".repeat(3 * (8 - len)),
|
|
||||||
" ".repeat(1 + 3 * 8)
|
|
||||||
)?;
|
|
||||||
} else {
|
|
||||||
write!(self.stdout, "{}│", " ".repeat(3 * (16 - len)))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut idx = 1;
|
|
||||||
for b in self.line.iter().map(|b| Byte(*b)) {
|
|
||||||
let chr = format!("{}", b.as_char());
|
|
||||||
write!(self.stdout, "{}", b.color().paint(chr)).ok();
|
|
||||||
|
|
||||||
if idx == 8 {
|
|
||||||
write!(self.stdout, "┊");
|
|
||||||
}
|
|
||||||
|
|
||||||
idx += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if len < 8 {
|
|
||||||
writeln!(
|
|
||||||
self.stdout,
|
|
||||||
"{}┊{}│ ",
|
|
||||||
" ".repeat(8 - len),
|
|
||||||
" ".repeat(8)
|
|
||||||
)?;
|
|
||||||
} else {
|
|
||||||
writeln!(self.stdout, "{}│", " ".repeat(16 - len))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.line.clear();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run() -> io::Result<()> {
|
|
||||||
let app = App::new(crate_name!())
|
|
||||||
.setting(AppSettings::ColorAuto)
|
|
||||||
.setting(AppSettings::ColoredHelp)
|
|
||||||
.setting(AppSettings::DeriveDisplayOrder)
|
|
||||||
.setting(AppSettings::UnifiedHelpMessage)
|
|
||||||
.version(crate_version!())
|
|
||||||
.about(crate_description!())
|
|
||||||
.arg(Arg::with_name("file").help("File to display"))
|
|
||||||
.arg(
|
|
||||||
Arg::with_name("length")
|
|
||||||
.short("n")
|
|
||||||
.long("length")
|
|
||||||
.takes_value(true)
|
|
||||||
.value_name("N")
|
|
||||||
.help("read only N bytes from the input"),
|
|
||||||
);
|
|
||||||
|
|
||||||
let matches = app.get_matches();
|
|
||||||
|
|
||||||
let stdin = io::stdin();
|
|
||||||
|
|
||||||
let mut reader: Box<dyn Read> = match matches.value_of("file") {
|
|
||||||
Some(filename) => Box::new(File::open(filename)?),
|
|
||||||
None => Box::new(stdin.lock()),
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(length) = matches
|
|
||||||
.value_of("length")
|
|
||||||
.and_then(|n| n.parse::<u64>().ok())
|
|
||||||
{
|
|
||||||
reader = Box::new(reader.take(length));
|
|
||||||
}
|
|
||||||
|
|
||||||
let stdout = io::stdout();
|
|
||||||
let mut printer = Printer::new(stdout.lock());
|
|
||||||
printer.header();
|
|
||||||
|
|
||||||
let mut buffer = [0; BUFFER_SIZE];
|
|
||||||
loop {
|
|
||||||
let size = reader.read(&mut buffer)?;
|
|
||||||
if size == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for b in &buffer[..size] {
|
|
||||||
let res = printer.print_byte(*b);
|
|
||||||
|
|
||||||
if res.is_err() {
|
|
||||||
// Broken pipe
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finish last line
|
|
||||||
printer.print_textline().ok();
|
|
||||||
printer.footer();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// Enable ANSI support for Windows
|
|
||||||
#[cfg(windows)]
|
|
||||||
let _ = ansi_term::enable_ansi_support();
|
|
||||||
|
|
||||||
let result = run();
|
|
||||||
match result {
|
|
||||||
Err(err) => {
|
|
||||||
eprintln!("Error: {}", err);
|
|
||||||
std::process::exit(1);
|
|
||||||
}
|
|
||||||
Ok(()) => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+423
@@ -0,0 +1,423 @@
|
|||||||
|
#[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,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub enum SqueezeAction {
|
||||||
|
Ignore,
|
||||||
|
Print,
|
||||||
|
Delete,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// line size
|
||||||
|
const LSIZE: usize = 16;
|
||||||
|
|
||||||
|
impl Squeezer {
|
||||||
|
pub fn new(enabled: bool) -> Squeezer {
|
||||||
|
Squeezer {
|
||||||
|
state: if enabled {
|
||||||
|
SqueezeState::Probe
|
||||||
|
} else {
|
||||||
|
SqueezeState::Disabled
|
||||||
|
},
|
||||||
|
byte: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process(&mut self, b: u8, i: usize) {
|
||||||
|
use self::SqueezeState::*;
|
||||||
|
if self.state == Disabled {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let eq = b == self.byte;
|
||||||
|
|
||||||
|
if i % 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 % LSIZE == 1 {
|
||||||
|
self.state = Probe;
|
||||||
|
} else if i % LSIZE != 1 {
|
||||||
|
self.state = NoSqueeze;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.byte = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn active(&self) -> bool {
|
||||||
|
use self::SqueezeState::*;
|
||||||
|
match self.state {
|
||||||
|
Squeeze | SqueezeActive | SqueezeFirstLine | SqueezeActiveFirstLine => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn three_same_lines() {
|
||||||
|
const LINES: usize = 3;
|
||||||
|
let v = vec![0u8; LINES * LSIZE];
|
||||||
|
let mut s = Squeezer::new(true);
|
||||||
|
// 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 line = 0;
|
||||||
|
let mut idx = 1;
|
||||||
|
for z in v.chunks(LSIZE) {
|
||||||
|
for i in z {
|
||||||
|
s.process(*i, idx);
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
let action = s.action();
|
||||||
|
s.advance();
|
||||||
|
assert_eq!(action, exp[line]);
|
||||||
|
line += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn incomplete_while_squeeze() {
|
||||||
|
// fourth line only has 12 bytes and should be printed
|
||||||
|
let v = vec![0u8; 3 * LSIZE + 12];
|
||||||
|
let mut s = Squeezer::new(true);
|
||||||
|
// 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 line = 0;
|
||||||
|
let mut idx = 1;
|
||||||
|
for z in v.chunks(LSIZE) {
|
||||||
|
for i in z {
|
||||||
|
s.process(*i, idx);
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
assert_eq!(s.action(), exp[line]);
|
||||||
|
s.advance();
|
||||||
|
line += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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);
|
||||||
|
// 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 line = 0;
|
||||||
|
let mut idx = 1;
|
||||||
|
for z in v.chunks(LSIZE) {
|
||||||
|
for i in z {
|
||||||
|
s.process(*i, idx);
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
let action = s.action();
|
||||||
|
assert_eq!(action, exp[line]);
|
||||||
|
s.advance();
|
||||||
|
line += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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];
|
||||||
|
v.extend(vec![1u8; 16]);
|
||||||
|
|
||||||
|
let mut s = Squeezer::new(true);
|
||||||
|
// 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 line = 0;
|
||||||
|
let mut idx = 1;
|
||||||
|
for z in v.chunks(LSIZE) {
|
||||||
|
for i in z {
|
||||||
|
s.process(*i, idx);
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
let action = s.action();
|
||||||
|
s.advance();
|
||||||
|
assert_eq!(action, exp[line]);
|
||||||
|
line += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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];
|
||||||
|
v.extend(vec![0u8; 8]);
|
||||||
|
v.extend(vec![1u8; 8]);
|
||||||
|
|
||||||
|
let mut s = Squeezer::new(true);
|
||||||
|
// 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 line = 0;
|
||||||
|
let mut idx = 1;
|
||||||
|
for z in v.chunks(LSIZE) {
|
||||||
|
for i in z {
|
||||||
|
s.process(*i, idx);
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
let action = s.action();
|
||||||
|
s.advance();
|
||||||
|
assert_eq!(action, exp[line]);
|
||||||
|
line += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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);
|
||||||
|
// 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 line = 0;
|
||||||
|
let mut idx = 1;
|
||||||
|
for z in v.chunks(LSIZE) {
|
||||||
|
for i in z {
|
||||||
|
s.process(*i, idx);
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
let action = s.action();
|
||||||
|
s.advance();
|
||||||
|
assert_eq!(action, exp[line]);
|
||||||
|
line += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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);
|
||||||
|
// 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 line = 0;
|
||||||
|
let mut idx = 1;
|
||||||
|
for z in v.chunks(LSIZE) {
|
||||||
|
for i in z {
|
||||||
|
s.process(*i, idx);
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
let action = s.action();
|
||||||
|
s.advance();
|
||||||
|
assert_eq!(action, exp[line]);
|
||||||
|
line += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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);
|
||||||
|
// 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 line = 0;
|
||||||
|
let mut idx = 1;
|
||||||
|
for z in v.chunks(LSIZE) {
|
||||||
|
for i in z {
|
||||||
|
s.process(*i, idx);
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
assert_eq!(s.action(), exp[line]);
|
||||||
|
s.advance();
|
||||||
|
line += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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);
|
||||||
|
// 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 line = 0;
|
||||||
|
let mut idx = 1;
|
||||||
|
for z in v.chunks(LSIZE) {
|
||||||
|
for i in z {
|
||||||
|
s.process(*i, idx);
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
assert_eq!(s.action(), exp[line]);
|
||||||
|
s.advance();
|
||||||
|
line += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user