From da2d5720fb9f7ac167f860ab9d49a45b45f92e62 Mon Sep 17 00:00:00 2001 From: Mario Reder Date: Wed, 29 Apr 2020 08:22:03 +0200 Subject: [PATCH 1/4] feat: add skip option resolves #16 and #87 --- src/bin/hexyl.rs | 33 +++++++++++++++++++++++++-------- src/input.rs | 38 ++++++++++++++++++++++++++++++++++++++ src/lib.rs | 5 ++++- 3 files changed, 67 insertions(+), 9 deletions(-) create mode 100644 src/input.rs diff --git a/src/bin/hexyl.rs b/src/bin/hexyl.rs index acc6a280..db0a82d3 100644 --- a/src/bin/hexyl.rs +++ b/src/bin/hexyl.rs @@ -3,14 +3,15 @@ extern crate clap; use atty; +use std::cell::RefCell; use std::fs::File; -use std::io::{self, prelude::*}; +use std::io::{self, prelude::*, SeekFrom}; use clap::{App, AppSettings, Arg}; use atty::Stream; -use hexyl::{BorderStyle, Printer}; +use hexyl::{BorderStyle, Input, Printer}; fn run() -> Result<(), Box> { let app = App::new(crate_name!()) @@ -37,6 +38,14 @@ fn run() -> Result<(), Box> { .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 first N bytes"), + ) .arg( Arg::with_name("nosqueezing") .short("v") @@ -80,17 +89,25 @@ fn run() -> Result<(), Box> { let stdin = io::stdin(); - let mut reader: Box = match matches.value_of("file") { - Some(filename) => Box::new(File::open(filename)?), - None => Box::new(stdin.lock()), + let mut reader: Input = match matches.value_of("file") { + Some(filename) => Input::File(File::open(filename)?), + None => Input::Stdin(RefCell::new(stdin.lock())), }; - let length_arg = matches.value_of("length").or(matches.value_of("bytes")); + let skip_arg = matches.value_of("skip"); - if let Some(length) = length_arg.and_then(parse_hex_or_int) { - reader = Box::new(reader.take(length)); + if let Some(length) = skip_arg.and_then(parse_hex_or_int) { + reader.seek(SeekFrom::Start(length))?; } + let length_arg = matches.value_of("length").or(matches.value_of("bytes")); + + let mut reader = if let Some(length) = length_arg.and_then(parse_hex_or_int) { + Box::new(reader.take(length)) + } else { + reader.into_inner() + }; + let show_color = match matches.value_of("color") { Some("never") => false, Some("auto") => atty::is(Stream::Stdout), diff --git a/src/input.rs b/src/input.rs new file mode 100644 index 00000000..131541aa --- /dev/null +++ b/src/input.rs @@ -0,0 +1,38 @@ +use std::cell::RefCell; +use std::fs; +use std::io::{self, Read, Seek, SeekFrom}; + +pub enum Input<'a> { + File(fs::File), + Stdin(RefCell>), +} + +impl<'a> Read for Input<'a> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + match *self { + Input::File(ref mut file) => file.read(buf), + Input::Stdin(ref mut stdin) => stdin.borrow_mut().read(buf), + } + } +} + +impl<'a> Seek for Input<'a> { + fn seek(&mut self, pos: SeekFrom) -> io::Result { + match *self { + Input::File(ref mut file) => file.seek(pos), + Input::Stdin(_) => Err(io::Error::new( + io::ErrorKind::Other, + "not supported by stdin-input", + )), + } + } +} + +impl<'a> Input<'a> { + pub fn into_inner(self) -> Box { + match self { + Self::File(file) => Box::new(file), + Self::Stdin(stdin) => Box::new(stdin.into_inner()), + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 08fd4d87..c8181073 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,8 @@ +pub(crate) mod input; pub mod squeezer; +pub use input::*; + use std::io::{self, Read, Write}; use ansi_term::Color; @@ -407,7 +410,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> { /// is exhausted. pub fn print_all( &mut self, - mut reader: Reader + mut reader: Reader, ) -> Result<(), Box> { let mut buffer = [0; BUFFER_SIZE]; 'mainloop: loop { From daa29e3a65ed22da52362082d1317a2e5c54cdc8 Mon Sep 17 00:00:00 2001 From: sharkdp Date: Thu, 30 Apr 2020 09:08:41 +0200 Subject: [PATCH 2/4] Remove unnecessary RefCell, backport to Rust 1.36 --- .travis.yml | 2 +- README.md | 2 +- src/bin/hexyl.rs | 3 +-- src/input.rs | 9 ++++----- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 164405b1..93d74138 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ matrix: # Minimum Rust supported channel. - os: linux - rust: 1.31.0 + rust: 1.36.0 env: TARGET=x86_64-unknown-linux-gnu diff --git a/README.md b/README.md index 10d8dc99..be5ac387 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ 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 ``` diff --git a/src/bin/hexyl.rs b/src/bin/hexyl.rs index db0a82d3..a9e8bb99 100644 --- a/src/bin/hexyl.rs +++ b/src/bin/hexyl.rs @@ -3,7 +3,6 @@ extern crate clap; use atty; -use std::cell::RefCell; use std::fs::File; use std::io::{self, prelude::*, SeekFrom}; @@ -91,7 +90,7 @@ fn run() -> Result<(), Box> { let mut reader: Input = match matches.value_of("file") { Some(filename) => Input::File(File::open(filename)?), - None => Input::Stdin(RefCell::new(stdin.lock())), + None => Input::Stdin(stdin.lock()), }; let skip_arg = matches.value_of("skip"); diff --git a/src/input.rs b/src/input.rs index 131541aa..4de746bf 100644 --- a/src/input.rs +++ b/src/input.rs @@ -1,17 +1,16 @@ -use std::cell::RefCell; use std::fs; use std::io::{self, Read, Seek, SeekFrom}; pub enum Input<'a> { File(fs::File), - Stdin(RefCell>), + Stdin(io::StdinLock<'a>), } impl<'a> Read for Input<'a> { fn read(&mut self, buf: &mut [u8]) -> io::Result { match *self { Input::File(ref mut file) => file.read(buf), - Input::Stdin(ref mut stdin) => stdin.borrow_mut().read(buf), + Input::Stdin(ref mut stdin) => stdin.read(buf), } } } @@ -31,8 +30,8 @@ impl<'a> Seek for Input<'a> { impl<'a> Input<'a> { pub fn into_inner(self) -> Box { match self { - Self::File(file) => Box::new(file), - Self::Stdin(stdin) => Box::new(stdin.into_inner()), + Input::File(file) => Box::new(file), + Input::Stdin(stdin) => Box::new(stdin), } } } From f6730cb3ed9b543c77be0a58ee092d14dd5bd011 Mon Sep 17 00:00:00 2001 From: Mario Reder Date: Tue, 12 May 2020 06:45:22 +0200 Subject: [PATCH 3/4] skip option error messages and display offset --- src/bin/hexyl.rs | 8 ++++---- src/input.rs | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/bin/hexyl.rs b/src/bin/hexyl.rs index a9e8bb99..de872047 100644 --- a/src/bin/hexyl.rs +++ b/src/bin/hexyl.rs @@ -93,10 +93,10 @@ fn run() -> Result<(), Box> { None => Input::Stdin(stdin.lock()), }; - let skip_arg = matches.value_of("skip"); + let skip_arg = matches.value_of("skip").and_then(parse_hex_or_int); - if let Some(length) = skip_arg.and_then(parse_hex_or_int) { - reader.seek(SeekFrom::Start(length))?; + if let Some(skip) = skip_arg { + reader.seek(SeekFrom::Start(skip))?; } let length_arg = matches.value_of("length").or(matches.value_of("bytes")); @@ -124,7 +124,7 @@ fn run() -> Result<(), Box> { let display_offset = matches .value_of("display_offset") .and_then(parse_hex_or_int) - .unwrap_or(0); + .unwrap_or(skip_arg.unwrap_or(0)); let stdout = io::stdout(); let mut stdout_lock = stdout.lock(); diff --git a/src/input.rs b/src/input.rs index 4de746bf..fd54d149 100644 --- a/src/input.rs +++ b/src/input.rs @@ -18,10 +18,21 @@ impl<'a> Read for Input<'a> { impl<'a> Seek for Input<'a> { fn seek(&mut self, pos: SeekFrom) -> io::Result { match *self { - Input::File(ref mut file) => file.seek(pos), + Input::File(ref mut file) => { + let seek_res = file.seek(pos); + if let Err(Some(29)) = seek_res.as_ref().map_err(|err| err.raw_os_error()) { + return Err(io::Error::new( + io::ErrorKind::Other, + "Using '--seek' is not supported when using a pipe", + ) + .into()); + }; + dbg!(&seek_res); + seek_res + } Input::Stdin(_) => Err(io::Error::new( io::ErrorKind::Other, - "not supported by stdin-input", + "Using '--seek' is not supported when reading from STDIN", )), } } From 3d75222f3fc0e783613510c71ca735b2c812b2eb Mon Sep 17 00:00:00 2001 From: Mario Reder Date: Wed, 13 May 2020 17:52:15 +0200 Subject: [PATCH 4/4] fix review comments --- Cargo.lock | 1 + Cargo.toml | 1 + src/input.rs | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7fdae6da..bed4b173 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,6 +61,7 @@ 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)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b9b4c8d1..ebde78db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ edition = "2018" [dependencies] ansi_term = "0.12" atty = "0.2" +libc = "0.2" [dependencies.clap] version = "2" diff --git a/src/input.rs b/src/input.rs index fd54d149..9d8268d9 100644 --- a/src/input.rs +++ b/src/input.rs @@ -20,14 +20,14 @@ impl<'a> Seek for Input<'a> { match *self { Input::File(ref mut file) => { let seek_res = file.seek(pos); - if let Err(Some(29)) = seek_res.as_ref().map_err(|err| err.raw_os_error()) { + if let Err(Some(libc::ESPIPE)) = seek_res.as_ref().map_err(|err| err.raw_os_error()) + { return Err(io::Error::new( io::ErrorKind::Other, "Using '--seek' is not supported when using a pipe", ) .into()); }; - dbg!(&seek_res); seek_res } Input::Stdin(_) => Err(io::Error::new(