mirror of
https://github.com/sharkdp/hexyl.git
synced 2026-10-29 08:05:57 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8f410b8ee | ||
|
|
7307077a66 | ||
|
|
3ca002638c | ||
|
|
ccfceaf58c | ||
|
|
751b670d5b | ||
|
|
478cc25ffd | ||
|
|
b1c4b0bf2b | ||
|
|
1951c59b0c | ||
|
|
ddc3a5c04a | ||
|
|
6d5c61b671 | ||
|
|
c5c8d1190f | ||
|
|
1459616d27 | ||
|
|
8af8a94699 | ||
|
|
07cdc97e74 | ||
|
|
bcca1fae03 | ||
|
|
48ad95efe6 | ||
|
|
3b3889967c | ||
|
|
57f1fb4dc4 | ||
|
|
ef40be0d53 | ||
|
|
6b235b1d2e | ||
|
|
7cff10b274 | ||
|
|
5327b71215 | ||
|
|
c336259159 | ||
|
|
133fdd9156 | ||
|
|
244f71691d | ||
|
|
6f73f4c0f0 | ||
|
|
7843b2d038 | ||
|
|
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 |
No files matched your search
+5
-4
@@ -14,11 +14,11 @@ matrix:
|
||||
env: TARGET=x86_64-apple-darwin
|
||||
- os: windows
|
||||
rust: stable
|
||||
env: TARGET=x86_64-pc-windows-msvc
|
||||
env: TARGET=x86_64-pc-windows-gnu
|
||||
|
||||
# Minimum Rust supported channel.
|
||||
- os: linux
|
||||
rust: 1.31.0
|
||||
rust: 1.36.0
|
||||
env: TARGET=x86_64-unknown-linux-gnu
|
||||
|
||||
|
||||
@@ -43,7 +43,8 @@ install:
|
||||
script:
|
||||
# Incorporate TARGET env var to the build and test process
|
||||
- cargo build --target $TARGET --verbose
|
||||
#- cargo test --target $TARGET --verbose
|
||||
- cargo test --target $TARGET --verbose
|
||||
- cargo run --target $TARGET --example=simple
|
||||
|
||||
before_deploy:
|
||||
- bash ci/before_deploy.bash
|
||||
@@ -72,7 +73,7 @@ deploy:
|
||||
# deploy only if we push a tag
|
||||
tags: true
|
||||
# deploy only on stable channel that has TARGET env variable sets
|
||||
condition: $TRAVIS_RUST_VERSION = stable && $TARGET != "x86_64-pc-windows-msvc"
|
||||
condition: $TRAVIS_RUST_VERSION = stable && $TARGET != "x86_64-pc-windows-gnu"
|
||||
|
||||
notifications:
|
||||
email:
|
||||
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
# v0.8.0
|
||||
|
||||
## Features
|
||||
|
||||
- A new `--skip <N>` / `-s <N>` option can be used to skip the first `N` bytes of the input, see #16, #88 (@Tarnadas, @MaxJohansen, @ErichDonGubler)
|
||||
- The `--length`/`--bytes`/`--skip`/`--display-offset` options can now take units for their value argument, for example:
|
||||
``` bash
|
||||
hexyl /dev/random --length=1KiB
|
||||
hexyl $(which hexyl) --skip=1MiB --length=10KiB
|
||||
```
|
||||
Both decimal SI prefixes (kB, MB, …) as well as binary IEC prefixes (KiB, MiB, …) are supported.
|
||||
In addition, there is a new `--block-size <SIZE>` option that can be used to control the size of the `block`
|
||||
unit:
|
||||
``` bash
|
||||
hexyl /dev/random --block-size=4kB --length=2block
|
||||
```
|
||||
See: #44 (@ErichDonGubler and @aswild)
|
||||
|
||||
## Other
|
||||
|
||||
- Various improvements throughout the code base by @ErichDonGubler
|
||||
|
||||
## Packaging
|
||||
|
||||
- `hexyl` is now available on Void Linux, see #91 (@notramo)
|
||||
|
||||
# v0.7.0
|
||||
|
||||
## Bugfixes
|
||||
|
||||
- hexyl can now be closed with `Ctrl-C` when reading input from STDIN, see #84
|
||||
|
||||
## Changes
|
||||
|
||||
- Breaking change (library): [`Printer::print_all`](https://docs.rs/hexyl/latest/hexyl/struct.Printer.html#method.print_all) does not take a second argument anymore.
|
||||
- Added an example on how to use `hexyl` as a library: https://github.com/sharkdp/hexyl/blob/v0.7.0/examples/simple.rs
|
||||
|
||||
# v0.6.0
|
||||
|
||||
## Features
|
||||
|
||||
- `hexyl` can now be used as a library, see #67 (@tommilligan)
|
||||
|
||||
- Added a new `-o`/`--display-offset` option to add a certain offset to the
|
||||
reported file positions, see #57 (@tommilligan)
|
||||
|
||||
## Bugfixes
|
||||
|
||||
- Remove additional space on short input, see #69 (@nalshihabi)
|
||||
|
||||
## Other
|
||||
|
||||
- Performance improvements, see #73 and #66
|
||||
|
||||
# v0.5.1
|
||||
|
||||
## Bugfixes
|
||||
|
||||
- A bug in the squeezing logic caused a wrong hexdump, see #62 (@awidegreen)
|
||||
- Some colors are printed even if they're disabled, see #64 (@awidegreen)
|
||||
- Fixed build failure on OpenBSD 6.5, see #61
|
||||
|
||||
# v0.5.0
|
||||
|
||||
## Features
|
||||
|
||||
- Added support for squeezing where reoccuring lines are squashed together and visualized with an asterisk. A new `-v`/`--no-squeezing` option can be used to disable the feature. For details, see #59 (@awidegreen)
|
||||
- Added a new `--border` option with support for various styles (Unicode, ASCII, None), see #54 (@dmke)
|
||||
- The `--length`/`-n` argument can be passed as a hexadecimal number (`hexyl -n 0xff /dev/urandom`), see #45 (@Qyriad)
|
||||
- Added `--bytes`/`-c` as an alias for `--length`/`-n`, see #48 (@selfup)
|
||||
|
||||
## Changes
|
||||
|
||||
- Print header immediately before the first line, see #51 (@mziter)
|
||||
|
||||
|
||||
# v0.4.0
|
||||
|
||||
## Features
|
||||
|
||||
- Added a new `--color=always/auto/never` option which can be used
|
||||
to control `hexyl`s color output, see #30 (@bennetthardwick)
|
||||
- Use 16 colors instead of 256, see #38
|
||||
|
||||
## Changes
|
||||
|
||||
- Various speed improvements, see #33 (@kballard)
|
||||
|
||||
## Bugfixes
|
||||
|
||||
- Proper Ctrl-C handling, see #35
|
||||
- Proper handling of broken pipes (`hexyl … | head`)
|
||||
|
||||
# v0.3.1
|
||||
|
||||
- Various (huge) performance improvements, see #23 and #24 (@kballard)
|
||||
- Replaced 24-bit truecolor ANSI codes by 8-bit codes to support
|
||||
more terminal emulators, fixes #9
|
||||
|
||||
# v0.3.0
|
||||
|
||||
Windows support
|
||||
|
||||
# v0.2.0
|
||||
|
||||
Initial release
|
||||
Generated
+47
-119
@@ -5,107 +5,70 @@ name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.7 (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]]
|
||||
name = "atty"
|
||||
version = "0.2.11"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.7"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.0"
|
||||
version = "2.33.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.1 (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.2 (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)",
|
||||
"vec_map 0.8.1 (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.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ctrlc"
|
||||
version = "3.1.1"
|
||||
name = "hermit-abi"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hexyl"
|
||||
version = "0.5.0"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"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.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.51"
|
||||
version = "0.2.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.54"
|
||||
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.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
@@ -113,22 +76,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "term_size"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.51 (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.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -136,44 +88,29 @@ name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"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)",
|
||||
"term_size 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.5"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.7"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
@@ -186,26 +123,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"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 bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83"
|
||||
"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
|
||||
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
||||
"checksum ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "630391922b1b893692c6334369ff528dcc3a9d8061ccf4c803aa8f83cb13db5e"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917"
|
||||
"checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17"
|
||||
"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
|
||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||
"checksum ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
|
||||
"checksum hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71"
|
||||
"checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
|
||||
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
"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 term_size 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9"
|
||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
"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 void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
||||
"checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||
"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"
|
||||
+7
-3
@@ -7,14 +7,18 @@ license = "MIT/Apache-2.0"
|
||||
name = "hexyl"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/sharkdp/hexyl"
|
||||
version = "0.5.0"
|
||||
version = "0.8.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
ansi_term = "0.11"
|
||||
ansi_term = "0.12"
|
||||
atty = "0.2"
|
||||
ctrlc = "3.1"
|
||||
libc = "0.2"
|
||||
|
||||
[dependencies.clap]
|
||||
version = "2"
|
||||
features = ["suggestions", "color", "wrap_help"]
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
@@ -19,13 +19,31 @@ of bytes (NULL bytes, printable ASCII characters, ASCII whitespace characters, o
|
||||
|
||||
## 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
|
||||
wget "https://github.com/sharkdp/hexyl/releases/download/v0.5.0/hexyl_0.5.0_amd64.deb"
|
||||
sudo dpkg -i hexyl_0.5.0_amd64.deb
|
||||
sudo dpkg -i hexyl_0.7.0_amd64.deb # adapt version number and architecture
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
You can install `hexyl` from [the official package repository](https://www.archlinux.org/packages/community/x86_64/hexyl/):
|
||||
@@ -34,6 +52,11 @@ You can install `hexyl` from [the official package repository](https://www.archl
|
||||
pacman -S hexyl
|
||||
```
|
||||
|
||||
### On Void Linux
|
||||
```
|
||||
xbps-install hexyl
|
||||
```
|
||||
|
||||
### On macOS
|
||||
|
||||
```
|
||||
@@ -58,12 +81,13 @@ Check out the [release page](https://github.com/sharkdp/hexyl/releases) for bina
|
||||
|
||||
### 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 PowerShell on Windows 10).
|
||||
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
|
||||
|
||||
If you have Rust 1.31 or higher, you can install `hexyl` from source via `cargo`:
|
||||
If you have Rust 1.36 or higher, you can install `hexyl` from source via `cargo`:
|
||||
```
|
||||
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,352 @@
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::fs::File;
|
||||
use std::io::{self, prelude::*, SeekFrom};
|
||||
|
||||
use clap::{App, AppSettings, Arg};
|
||||
|
||||
use atty::Stream;
|
||||
|
||||
use hexyl::{BorderStyle, Input, 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("The file to display. If no FILE argument is given, read from STDIN."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("length")
|
||||
.short("n")
|
||||
.long("length")
|
||||
.takes_value(true)
|
||||
.value_name("N")
|
||||
.help(
|
||||
"Only read N bytes from the input. The N argument can also include a \
|
||||
unit with a decimal prefix (kB, MB, ..) or binary prefix (kiB, MiB, ..).\n\
|
||||
Examples: --length=64, --length=4KiB",
|
||||
),
|
||||
)
|
||||
.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("skip")
|
||||
.short("s")
|
||||
.long("skip")
|
||||
.takes_value(true)
|
||||
.value_name("N")
|
||||
.help(
|
||||
"Skip the first N bytes of the input. The N argument can also include \
|
||||
a unit (see `--length` for details)",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("block_size")
|
||||
.long("block-size")
|
||||
.takes_value(true)
|
||||
.value_name("SIZE")
|
||||
.help(
|
||||
"Sets the size of the `block` unit to SIZE.\n\
|
||||
Examples: --block-size=1024, --block-size=4kB",
|
||||
),
|
||||
)
|
||||
.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)
|
||||
.value_name("STYLE")
|
||||
.possible_values(&["unicode", "ascii", "none"])
|
||||
.default_value("unicode")
|
||||
.help("Whether to draw a border with Unicode characters, ASCII characters, or none at all"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("display_offset")
|
||||
.short("o")
|
||||
.long("display-offset")
|
||||
.takes_value(true)
|
||||
.value_name("N")
|
||||
.help("Add N bytes to the displayed file position. The N argument can also include \
|
||||
a unit (see `--length` for details)"),
|
||||
);
|
||||
|
||||
let matches = app.get_matches_safe()?;
|
||||
|
||||
let stdin = io::stdin();
|
||||
|
||||
let mut reader: Input = match matches.value_of("FILE") {
|
||||
Some(filename) => Input::File(File::open(filename)?),
|
||||
None => Input::Stdin(stdin.lock()),
|
||||
};
|
||||
|
||||
let block_size = matches
|
||||
.value_of("block_size")
|
||||
.and_then(|bs| bs.parse().ok().and_then(PositiveI64::new))
|
||||
.unwrap_or_else(|| PositiveI64::new(512).unwrap());
|
||||
|
||||
let skip_arg = matches
|
||||
.value_of("skip")
|
||||
.and_then(|s| parse_byte_count(s, block_size));
|
||||
|
||||
if let Some(skip) = skip_arg {
|
||||
reader.seek(SeekFrom::Current(skip.into_inner()))?;
|
||||
}
|
||||
|
||||
let length_arg = matches
|
||||
.value_of("length")
|
||||
.or_else(|| matches.value_of("bytes"));
|
||||
|
||||
let mut reader = if let Some(length) = length_arg.and_then(|s| parse_byte_count(s, block_size))
|
||||
{
|
||||
Box::new(reader.take(length.into()))
|
||||
} else {
|
||||
reader.into_inner()
|
||||
};
|
||||
|
||||
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(|s| parse_byte_count(s, block_size))
|
||||
.or(skip_arg)
|
||||
.unwrap_or_default()
|
||||
.into();
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Hash, Eq, Ord, PartialEq, PartialOrd)]
|
||||
pub struct PositiveI64(i64);
|
||||
|
||||
impl PositiveI64 {
|
||||
pub fn new(x: i64) -> Option<Self> {
|
||||
if x.is_negative() {
|
||||
None
|
||||
} else {
|
||||
Some(Self(x))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> i64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u64> for PositiveI64 {
|
||||
fn into(self) -> u64 {
|
||||
u64::try_from(self.0)
|
||||
.expect("invariant broken: PositiveI64 should contain a positive i64 value")
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_byte_count(n: &str, block_size: PositiveI64) -> Option<PositiveI64> {
|
||||
const HEX_PREFIX: &str = "0x";
|
||||
|
||||
let n = {
|
||||
let mut chars = n.chars();
|
||||
match chars.next()? {
|
||||
'+' => chars.as_str(),
|
||||
'-' => return None,
|
||||
_ => n,
|
||||
}
|
||||
};
|
||||
|
||||
if n.starts_with(HEX_PREFIX) {
|
||||
let n = &n[HEX_PREFIX.len()..];
|
||||
match n.chars().next() {
|
||||
Some('+') | Some('-') => return None,
|
||||
_ => (),
|
||||
}
|
||||
return i64::from_str_radix(n, 16).ok().and_then(PositiveI64::new);
|
||||
}
|
||||
|
||||
let (n, unit_multiplier) = match n.chars().position(|c| !c.is_ascii_digit()) {
|
||||
Some(unit_begin_idx) => {
|
||||
let (n, raw_unit) = n.split_at(unit_begin_idx);
|
||||
let raw_unit = raw_unit.to_lowercase();
|
||||
(
|
||||
n,
|
||||
[
|
||||
("b", 1),
|
||||
("kb", 1000i64.pow(1)),
|
||||
("mb", 1000i64.pow(2)),
|
||||
("gb", 1000i64.pow(3)),
|
||||
("tb", 1000i64.pow(4)),
|
||||
("kib", 1024i64.pow(1)),
|
||||
("mib", 1024i64.pow(2)),
|
||||
("gib", 1024i64.pow(3)),
|
||||
("tib", 1024i64.pow(4)),
|
||||
("block", block_size.into_inner()),
|
||||
]
|
||||
.iter()
|
||||
.cloned()
|
||||
.find_map(|(unit, multiplier)| {
|
||||
if unit == raw_unit {
|
||||
Some(multiplier)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})?,
|
||||
)
|
||||
}
|
||||
None => (n, 1),
|
||||
};
|
||||
|
||||
n.parse::<i64>()
|
||||
.ok()?
|
||||
.checked_mul(unit_multiplier)
|
||||
.and_then(PositiveI64::new)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_byte_count() {
|
||||
macro_rules! success {
|
||||
($input: expr, $expected: expr) => {
|
||||
success!($input, 512, $expected)
|
||||
};
|
||||
($input: expr, $block_size: expr, $expected: expr) => {
|
||||
assert_eq!(
|
||||
parse_byte_count($input, PositiveI64::new($block_size).unwrap()),
|
||||
Some(PositiveI64::new($expected).unwrap())
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! error {
|
||||
($input: expr) => {
|
||||
assert_eq!(
|
||||
parse_byte_count($input, PositiveI64::new(512).unwrap()),
|
||||
None
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
success!("0", 0);
|
||||
success!("1", 1);
|
||||
success!("1", 1);
|
||||
success!("100", 100);
|
||||
success!("+100", 100);
|
||||
|
||||
success!("1KB", 1000);
|
||||
success!("2MB", 2000000);
|
||||
success!("3GB", 3000000000);
|
||||
success!("4TB", 4000000000000);
|
||||
success!("+4TB", 4000000000000);
|
||||
|
||||
success!("1GiB", 1073741824);
|
||||
success!("2TiB", 2199023255552);
|
||||
success!("+2TiB", 2199023255552);
|
||||
|
||||
success!("0xff", 255);
|
||||
success!("0xEE", 238);
|
||||
success!("+0xFF", 255);
|
||||
|
||||
success!("1block", 512, 512);
|
||||
success!("2block", 512, 1024);
|
||||
success!("1block", 4, 4);
|
||||
success!("2block", 4, 8);
|
||||
|
||||
// empty string is invalid
|
||||
error!("");
|
||||
// These are also bad.
|
||||
error!("+");
|
||||
error!("-");
|
||||
error!("K");
|
||||
error!("k");
|
||||
error!("m");
|
||||
error!("block");
|
||||
// leading/trailing space is invalid
|
||||
error!(" 0");
|
||||
error!("0 ");
|
||||
// Negatives make no sense for byte counts
|
||||
error!("-1");
|
||||
error!("0x-12");
|
||||
// This was previously accepted but shouldn't be.
|
||||
error!("0x+12");
|
||||
// invalid suffix
|
||||
error!("1234asdf");
|
||||
// bad numbers
|
||||
error!("asdf1234");
|
||||
error!("a1s2d3f4");
|
||||
// multiplication overflows u64
|
||||
error!("20000000TiB");
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
use std::convert::TryFrom;
|
||||
use std::fs;
|
||||
use std::io::{self, copy, sink, Read, Seek, SeekFrom};
|
||||
|
||||
pub enum Input<'a> {
|
||||
File(fs::File),
|
||||
Stdin(io::StdinLock<'a>),
|
||||
}
|
||||
|
||||
impl<'a> Read for Input<'a> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
match *self {
|
||||
Input::File(ref mut file) => file.read(buf),
|
||||
Input::Stdin(ref mut stdin) => stdin.read(buf),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Seek for Input<'a> {
|
||||
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
|
||||
fn try_skip<R>(reader: R, pos: SeekFrom, err_desc: &'static str) -> io::Result<u64>
|
||||
where
|
||||
R: Read,
|
||||
{
|
||||
let cant_seek_abs_err = || Err(io::Error::new(io::ErrorKind::Other, err_desc));
|
||||
|
||||
let offset = match pos {
|
||||
SeekFrom::Current(o) => u64::try_from(o).or_else(|_e| cant_seek_abs_err())?,
|
||||
SeekFrom::Start(_) | SeekFrom::End(_) => cant_seek_abs_err()?,
|
||||
};
|
||||
|
||||
copy(&mut reader.take(offset), &mut sink())
|
||||
}
|
||||
|
||||
match *self {
|
||||
Input::File(ref mut file) => {
|
||||
let seek_res = file.seek(pos);
|
||||
if let Err(Some(libc::ESPIPE)) = seek_res.as_ref().map_err(|err| err.raw_os_error())
|
||||
{
|
||||
try_skip(
|
||||
file,
|
||||
pos,
|
||||
"Pipes only support seeking forward with a relative offset",
|
||||
)
|
||||
} else {
|
||||
seek_res
|
||||
}
|
||||
}
|
||||
Input::Stdin(ref mut stdin) => try_skip(
|
||||
stdin,
|
||||
pos,
|
||||
"STDIN only supports seeking forward with a relative offset",
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Input<'a> {
|
||||
pub fn into_inner(self) -> Box<dyn Read + 'a> {
|
||||
match self {
|
||||
Input::File(file) => Box::new(file),
|
||||
Input::Stdin(stdin) => Box::new(stdin),
|
||||
}
|
||||
}
|
||||
}
|
||||
+179
-233
@@ -1,22 +1,13 @@
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
pub(crate) mod input;
|
||||
pub mod squeezer;
|
||||
|
||||
use atty;
|
||||
use ctrlc;
|
||||
pub use input::*;
|
||||
|
||||
mod squeezer;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{self, prelude::*, StdoutLock};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use clap::{App, AppSettings, Arg};
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
use ansi_term::Color;
|
||||
use ansi_term::Color::Fixed;
|
||||
|
||||
use atty::Stream;
|
||||
use crate::squeezer::{SqueezeAction, Squeezer};
|
||||
|
||||
const BUFFER_SIZE: usize = 256;
|
||||
@@ -28,7 +19,7 @@ const COLOR_ASCII_WHITESPACE: Color = Color::Green;
|
||||
const COLOR_ASCII_OTHER: Color = Color::Purple;
|
||||
const COLOR_NONASCII: Color = Color::Yellow;
|
||||
|
||||
enum ByteCategory {
|
||||
pub enum ByteCategory {
|
||||
Null,
|
||||
AsciiPrintable,
|
||||
AsciiWhitespace,
|
||||
@@ -43,10 +34,7 @@ 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()
|
||||
{
|
||||
} else if self.0.is_ascii_graphic() {
|
||||
ByteCategory::AsciiPrintable
|
||||
} else if self.0.is_ascii_whitespace() {
|
||||
ByteCategory::AsciiWhitespace
|
||||
@@ -90,7 +78,7 @@ struct BorderElements {
|
||||
right_corner: char,
|
||||
}
|
||||
|
||||
enum BorderStyle {
|
||||
pub enum BorderStyle {
|
||||
Unicode,
|
||||
Ascii,
|
||||
None,
|
||||
@@ -150,33 +138,34 @@ impl BorderStyle {
|
||||
}
|
||||
}
|
||||
|
||||
struct Printer<'a> {
|
||||
idx: usize,
|
||||
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 stdout.
|
||||
/// The buffered line built with each byte, ready to print to writer.
|
||||
buffer_line: Vec<u8>,
|
||||
stdout: StdoutLock<'a>,
|
||||
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: u64,
|
||||
}
|
||||
|
||||
impl<'a> Printer<'a> {
|
||||
fn new(
|
||||
stdout: StdoutLock<'_>,
|
||||
impl<'a, Writer: Write> Printer<'a, Writer> {
|
||||
pub fn new(
|
||||
writer: &'a mut Writer,
|
||||
show_color: bool,
|
||||
border_style: BorderStyle,
|
||||
use_squeeze: bool,
|
||||
) -> Printer<'_> {
|
||||
) -> Printer<'a, Writer> {
|
||||
Printer {
|
||||
idx: 1,
|
||||
raw_line: vec![],
|
||||
buffer_line: vec![],
|
||||
stdout,
|
||||
writer,
|
||||
show_color,
|
||||
border_style,
|
||||
header_was_printed: false,
|
||||
@@ -201,17 +190,23 @@ impl<'a> Printer<'a> {
|
||||
})
|
||||
.collect(),
|
||||
squeezer: Squeezer::new(use_squeeze),
|
||||
display_offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn header(&mut self) {
|
||||
pub fn display_offset(&mut self, display_offset: u64) -> &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.stdout,
|
||||
self.writer,
|
||||
"{l}{h8}{c}{h25}{c}{h25}{c}{h8}{c}{h8}{r}",
|
||||
l = border_elements.left_corner,
|
||||
c = border_elements.column_separator,
|
||||
@@ -223,14 +218,14 @@ impl<'a> Printer<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn footer(&mut self) {
|
||||
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.stdout,
|
||||
self.writer,
|
||||
"{l}{h8}{c}{h25}{c}{h25}{c}{h8}{c}{h8}{r}",
|
||||
l = border_elements.left_corner,
|
||||
c = border_elements.column_separator,
|
||||
@@ -249,7 +244,7 @@ impl<'a> Printer<'a> {
|
||||
}
|
||||
|
||||
let style = COLOR_OFFSET.normal();
|
||||
let byte_index = format!("{:08x}", self.idx - 1);
|
||||
let byte_index = format!("{:08x}", self.idx - 1 + self.display_offset);
|
||||
let formatted_string = if self.show_color {
|
||||
format!("{}", style.paint(byte_index))
|
||||
} else {
|
||||
@@ -264,7 +259,7 @@ impl<'a> Printer<'a> {
|
||||
);
|
||||
}
|
||||
|
||||
fn print_byte(&mut self, b: u8) -> io::Result<()> {
|
||||
pub fn print_byte(&mut self, b: u8) -> io::Result<()> {
|
||||
if self.idx % 16 == 1 {
|
||||
self.print_position_indicator();
|
||||
}
|
||||
@@ -289,7 +284,7 @@ impl<'a> Printer<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_textline(&mut self) -> io::Result<()> {
|
||||
pub fn print_textline(&mut self) -> io::Result<()> {
|
||||
let len = self.raw_line.len();
|
||||
|
||||
if len == 0 {
|
||||
@@ -305,74 +300,83 @@ impl<'a> Printer<'a> {
|
||||
self.border_style.inner_sep(),
|
||||
self.border_style.outer_sep(),
|
||||
);
|
||||
self.stdout.write_all(&self.buffer_line)?;
|
||||
self.writer.write_all(&self.buffer_line)?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
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 squeeze_action = self.squeezer.action();
|
||||
|
||||
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());
|
||||
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()
|
||||
);
|
||||
}
|
||||
|
||||
idx += 1;
|
||||
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()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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 self.squeezer.action() {
|
||||
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}",
|
||||
style.paint("*"),
|
||||
asterisk,
|
||||
"",
|
||||
7,
|
||||
25,
|
||||
@@ -385,171 +389,113 @@ impl<'a> Printer<'a> {
|
||||
SqueezeAction::Ignore => (),
|
||||
}
|
||||
|
||||
self.stdout.write_all(&self.buffer_line)?;
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
||||
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"),
|
||||
);
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::io;
|
||||
use std::str;
|
||||
|
||||
let matches = app.get_matches_safe()?;
|
||||
use super::*;
|
||||
|
||||
let stdin = io::stdin();
|
||||
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);
|
||||
|
||||
let mut reader: Box<dyn Read> = match matches.value_of("file") {
|
||||
Some(filename) => Box::new(File::open(filename)?),
|
||||
None => Box::new(stdin.lock()),
|
||||
};
|
||||
printer.print_all(input).unwrap();
|
||||
|
||||
let length_arg = matches.value_of("length").or(matches.value_of("bytes"));
|
||||
|
||||
if let Some(length) = length_arg.and_then(|n| {
|
||||
if n.starts_with("0x") {
|
||||
u64::from_str_radix(n.trim_start_matches("0x"), 16).ok()
|
||||
} else {
|
||||
n.parse::<u64>().ok()
|
||||
}
|
||||
}) {
|
||||
reader = Box::new(reader.take(length));
|
||||
let actual_string: &str = str::from_utf8(&output).unwrap();
|
||||
assert_eq!(actual_string, expected_string)
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
// Set up Ctrl-C handler
|
||||
let cancelled = Arc::new(AtomicBool::new(false));
|
||||
let c = cancelled.clone();
|
||||
|
||||
ctrlc::set_handler(move || {
|
||||
c.store(true, Ordering::SeqCst);
|
||||
})
|
||||
.expect("Error setting Ctrl-C handler");
|
||||
|
||||
let stdout = io::stdout();
|
||||
let mut printer = Printer::new(stdout.lock(), show_color, border_style, squeeze);
|
||||
|
||||
let mut buffer = [0; BUFFER_SIZE];
|
||||
'mainloop: loop {
|
||||
let size = reader.read(&mut buffer)?;
|
||||
if size == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
if cancelled.load(Ordering::SeqCst) {
|
||||
eprintln!("hexyl has been cancelled.");
|
||||
std::process::exit(130); // Set exit code to 128 + SIGINT
|
||||
}
|
||||
|
||||
for b in &buffer[..size] {
|
||||
let res = printer.print_byte(*b);
|
||||
|
||||
if res.is_err() {
|
||||
// Broken pipe
|
||||
break 'mainloop;
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn empty_file_passes() {
|
||||
let input = io::empty();
|
||||
let expected_string = "\
|
||||
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
|
||||
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘
|
||||
"
|
||||
.to_owned();
|
||||
assert_print_all_output(input, expected_string);
|
||||
}
|
||||
|
||||
// Finish last line
|
||||
printer.print_textline().ok();
|
||||
if !printer.header_was_printed {
|
||||
printer.header();
|
||||
#[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);
|
||||
}
|
||||
printer.footer();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
#[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();
|
||||
|
||||
fn main() {
|
||||
// Enable ANSI support for Windows
|
||||
#[cfg(windows)]
|
||||
let _ = ansi_term::enable_ansi_support();
|
||||
let mut output = vec![];
|
||||
let mut printer: Printer<Vec<u8>> =
|
||||
Printer::new(&mut output, false, BorderStyle::Unicode, true);
|
||||
printer.display_offset(0xdeadbeef);
|
||||
|
||||
let result = run();
|
||||
printer.print_all(input).unwrap();
|
||||
|
||||
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);
|
||||
let actual_string: &str = str::from_utf8(&output).unwrap();
|
||||
assert_eq!(actual_string, expected_string)
|
||||
}
|
||||
}
|
||||
+218
-53
@@ -32,7 +32,7 @@ pub enum SqueezeAction {
|
||||
}
|
||||
|
||||
/// line size
|
||||
const LSIZE: usize = 16;
|
||||
const LSIZE: u64 = 16;
|
||||
|
||||
impl Squeezer {
|
||||
pub fn new(enabled: bool) -> Squeezer {
|
||||
@@ -46,7 +46,7 @@ impl Squeezer {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process(&mut self, b: u8, i: usize) {
|
||||
pub fn process(&mut self, b: u8, i: u64) {
|
||||
use self::SqueezeState::*;
|
||||
if self.state == Disabled {
|
||||
return;
|
||||
@@ -54,17 +54,23 @@ impl Squeezer {
|
||||
let eq = b == self.byte;
|
||||
|
||||
if i % LSIZE == 0 {
|
||||
self.state = match self.state {
|
||||
NoSqueeze => Probe,
|
||||
Probe => SqueezeActiveFirstLine,
|
||||
SqueezeActiveFirstLine => SqueezeFirstLine,
|
||||
SqueezeFirstLine => SqueezeActive,
|
||||
SqueezeActive => Squeeze,
|
||||
Squeeze => SqueezeActive,
|
||||
Disabled => Disabled,
|
||||
};
|
||||
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) || i % LSIZE != 1 {
|
||||
if i % LSIZE == 1 {
|
||||
self.state = Probe;
|
||||
} else if i % LSIZE != 1 {
|
||||
self.state = NoSqueeze;
|
||||
}
|
||||
}
|
||||
@@ -80,17 +86,23 @@ impl Squeezer {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn action(&mut self) -> SqueezeAction {
|
||||
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;
|
||||
SqueezeAction::Print
|
||||
}
|
||||
SqueezeState::Squeeze => {
|
||||
self.state = SqueezeState::SqueezeActive;
|
||||
SqueezeAction::Delete
|
||||
}
|
||||
_ => SqueezeAction::Ignore,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,13 +111,16 @@ impl Squeezer {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
const LSIZE_USIZE: usize = LSIZE as usize;
|
||||
|
||||
#[test]
|
||||
fn three_same_lines() {
|
||||
const LINES: usize = 3;
|
||||
let v = vec![0u8; LINES * LSIZE];
|
||||
let v = vec![0u8; LINES * LSIZE_USIZE];
|
||||
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
|
||||
@@ -113,22 +128,28 @@ mod tests {
|
||||
SqueezeAction::Delete, // delete reoccurring line
|
||||
];
|
||||
|
||||
for z in 0..LINES {
|
||||
for i in z * LSIZE..(z + 1) * LSIZE {
|
||||
s.process(v[i], i + 1);
|
||||
let mut line = 0;
|
||||
let mut idx = 1;
|
||||
for z in v.chunks(LSIZE_USIZE) {
|
||||
for i in z {
|
||||
s.process(*i, idx);
|
||||
idx += 1;
|
||||
}
|
||||
assert_eq!(s.action(), exp[z]);
|
||||
let action = s.action();
|
||||
s.advance();
|
||||
assert_eq!(action, exp[line]);
|
||||
line += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn incomplete_while_squeeze() {
|
||||
const LINES: usize = 3;
|
||||
// third line only has 12 bytes and should be printed
|
||||
let v = vec![0u8; LINES * LSIZE + 12];
|
||||
// fourth line only has 12 bytes and should be printed
|
||||
let v = vec![0u8; 3 * LSIZE_USIZE + 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
|
||||
@@ -137,23 +158,22 @@ mod tests {
|
||||
SqueezeAction::Ignore, // last line only 12 bytes, print it
|
||||
];
|
||||
|
||||
for z in 0..LINES {
|
||||
for i in z * LSIZE..(z + 1) * LSIZE {
|
||||
s.process(v[i], i + 1);
|
||||
let mut line = 0;
|
||||
let mut idx = 1;
|
||||
for z in v.chunks(LSIZE_USIZE) {
|
||||
for i in z {
|
||||
s.process(*i, idx);
|
||||
idx += 1;
|
||||
}
|
||||
assert_eq!(s.action(), exp[z]);
|
||||
assert_eq!(s.action(), exp[line]);
|
||||
s.advance();
|
||||
line += 1;
|
||||
}
|
||||
|
||||
for i in LSIZE * LINES..LINES * LSIZE + 12 {
|
||||
s.process(v[i], i + 1);
|
||||
}
|
||||
assert_eq!(s.action(), exp[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// all three lines are different, print all
|
||||
fn three_different_lines() {
|
||||
const LINES: usize = 3;
|
||||
let mut v: Vec<u8> = vec![];
|
||||
v.extend(vec![0u8; 16]);
|
||||
v.extend(vec![1u8; 16]);
|
||||
@@ -162,6 +182,7 @@ mod tests {
|
||||
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
|
||||
@@ -169,11 +190,17 @@ mod tests {
|
||||
SqueezeAction::Ignore, // different
|
||||
];
|
||||
|
||||
for z in 0..LINES {
|
||||
for i in z * LSIZE..(z + 1) * LSIZE {
|
||||
s.process(v[i], i + 1);
|
||||
let mut line = 0;
|
||||
let mut idx = 1;
|
||||
for z in v.chunks(LSIZE_USIZE) {
|
||||
for i in z {
|
||||
s.process(*i, idx);
|
||||
idx += 1;
|
||||
}
|
||||
assert_eq!(s.action(), exp[z]);
|
||||
let action = s.action();
|
||||
assert_eq!(action, exp[line]);
|
||||
s.advance();
|
||||
line += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,12 +209,13 @@ mod tests {
|
||||
/// print
|
||||
fn one_squeeze_no_delete() {
|
||||
const LINES: usize = 3;
|
||||
let mut v = vec![0u8; (LINES - 1) * LSIZE];
|
||||
let mut v = vec![0u8; (LINES - 1) * LSIZE_USIZE];
|
||||
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
|
||||
@@ -195,11 +223,17 @@ mod tests {
|
||||
SqueezeAction::Ignore, // different lines, print again
|
||||
];
|
||||
|
||||
for z in 0..LINES {
|
||||
for i in z * LSIZE..(z + 1) * LSIZE {
|
||||
s.process(v[i], i + 1);
|
||||
let mut line = 0;
|
||||
let mut idx = 1;
|
||||
for z in v.chunks(LSIZE_USIZE) {
|
||||
for i in z {
|
||||
s.process(*i, idx);
|
||||
idx += 1;
|
||||
}
|
||||
assert_eq!(s.action(), exp[z]);
|
||||
let action = s.action();
|
||||
s.advance();
|
||||
assert_eq!(action, exp[line]);
|
||||
line += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,31 +241,37 @@ mod tests {
|
||||
/// 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];
|
||||
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);
|
||||
// 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
|
||||
];
|
||||
|
||||
for z in 0..LINES {
|
||||
for i in z * LSIZE..(z + 1) * LSIZE {
|
||||
s.process(v[i], i + 1);
|
||||
let mut line = 0;
|
||||
let mut idx = 1;
|
||||
for z in v.chunks(LSIZE_USIZE) {
|
||||
for i in z {
|
||||
s.process(*i, idx);
|
||||
idx += 1;
|
||||
}
|
||||
assert_eq!(s.action(), exp[z]);
|
||||
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() {
|
||||
const LINES: usize = 3;
|
||||
let mut v = vec![];
|
||||
v.extend(vec![0u8; 8]);
|
||||
v.extend(vec![1u8; 8]);
|
||||
@@ -243,6 +283,7 @@ mod tests {
|
||||
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
|
||||
@@ -250,11 +291,135 @@ mod tests {
|
||||
SqueezeAction::Ignore, // print squeeze symbol
|
||||
];
|
||||
|
||||
for z in 0..LINES {
|
||||
for i in z * LSIZE..(z + 1) * LSIZE {
|
||||
s.process(v[i], i + 1);
|
||||
let mut line = 0;
|
||||
let mut idx = 1;
|
||||
for z in v.chunks(LSIZE_USIZE) {
|
||||
for i in z {
|
||||
s.process(*i, idx);
|
||||
idx += 1;
|
||||
}
|
||||
assert_eq!(s.action(), exp[z]);
|
||||
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_USIZE) {
|
||||
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_USIZE) {
|
||||
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_USIZE) {
|
||||
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