summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulian Sitkevich <1553398+sitkevij@users.noreply.github.com>2020-10-29 07:55:07 -0700
committerGitHub <noreply@github.com>2020-10-29 07:55:07 -0700
commitde4c13e8c3703773a746cff9df7cd02b3e8c7f8b (patch)
tree22d4cdace6b8eb2e949815d9b10325860cdf8aa3
parente62a3a6f70e1fa66848aa82611b53415b934104b (diff)
parent3e508eab230297a5b938ccbce7d2cdc5f3b43892 (diff)
Merge pull request #29 from sitkevij/developv0.3.1
develop 0.3.1
-rw-r--r--Cargo.lock69
-rw-r--r--Cargo.toml5
-rw-r--r--README.md2
-rw-r--r--src/lib.rs178
-rw-r--r--src/main.rs6
-rwxr-xr-xtests.sh14
6 files changed, 215 insertions, 59 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5c49a10..72c35c1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -9,6 +9,18 @@ dependencies = [
]
[[package]]
+name = "assert_cmd"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "doc-comment 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "predicates 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "predicates-tree 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "atty"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -38,10 +50,21 @@ dependencies = [
]
[[package]]
+name = "difference"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "doc-comment"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "hx"
-version = "0.3.0"
+version = "0.3.1"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "assert_cmd 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -51,6 +74,29 @@ version = "0.2.47"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "predicates"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "predicates-core"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "predicates-tree"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "treeline 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "redox_syscall"
version = "0.1.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -87,6 +133,11 @@ dependencies = [
]
[[package]]
+name = "treeline"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "unicode-width"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -97,6 +148,14 @@ version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "wait-timeout"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "winapi"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -117,17 +176,25 @@ 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 assert_cmd 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c88b9ca26f9c16ec830350d309397e74ee9abdfd8eb1f71cb6ecc71a3fc818da"
"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 clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
+"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
+"checksum doc-comment 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
"checksum libc 0.2.47 (registry+https://github.com/rust-lang/crates.io-index)" = "48450664a984b25d5b479554c29cc04e3150c97aa4c01da5604a2d4ed9151476"
+"checksum predicates 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96bfead12e90dccead362d62bb2c90a5f6fc4584963645bc7f71a735e0b0735a"
+"checksum predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "06075c3a3e92559ff8929e7a280684489ea27fe44805174c3ebd9328dcb37178"
+"checksum predicates-tree 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8e63c4859013b38a76eca2414c64911fba30def9e3202ac461a2d22831220124"
"checksum redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)" = "52ee9a534dc1301776eff45b4fa92d2c39b1d8c3d3357e6eb593e0d795506fc2"
"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 termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
+"checksum treeline 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
"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 wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
"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"
diff --git a/Cargo.toml b/Cargo.toml
index a1c0727..8d4ed10 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,7 +7,7 @@ repository = "https://github.com/sitkevij/hex"
keywords = ["hexdump", "hexadecimal", "tools", "ascii", "hex"]
license = "MIT"
name = "hx"
-version = "0.3.0"
+version = "0.3.1"
edition = "2018"
# see https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -30,3 +30,6 @@ opt-level = 3
[dependencies]
clap = "2.31.1"
ansi_term = "0.11"
+
+[dev-dependencies]
+assert_cmd = "1.0.1"
diff --git a/README.md b/README.md
index f1f8551..927cdc2 100644
--- a/README.md
+++ b/README.md
@@ -89,7 +89,7 @@ cargo install --path .
Which will compile the release version, run tests and install release binary to `<USERDIR>/.cargo/bin/hx`.
-If `<USERDIR>/.cargo/bin` is part of the `PATH` evironment variable, `hx` should be able to be executed anywhere in the shell.
+If `<USERDIR>/.cargo/bin` is part of the `PATH` environment variable, `hx` should be able to be executed anywhere in the shell.
## features
diff --git a/src/lib.rs b/src/lib.rs
index 3fb1e71..4002b1e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -21,7 +21,7 @@ use std::error::Error;
use std::f64;
use std::fs;
use std::io::BufReader;
-use std::io::{self, BufRead, Read};
+use std::io::{self, BufRead, Read, Write};
/// arg cols
pub const ARG_COL: &str = "cols";
@@ -134,8 +134,8 @@ pub fn offset(b: u64) -> String {
}
/// print offset to std out
-pub fn print_offset(b: u64) {
- print!("{}: ", offset(b));
+pub fn print_offset(w: &mut impl Write, b: u64) -> io::Result<()> {
+ write!(w, "{}: ", offset(b))
}
/// hex octal, takes u8
@@ -159,7 +159,7 @@ pub fn hex_binary(b: u8) -> String {
}
/// print byte to std out
-pub fn print_byte(b: u8, format: Format, colorize: bool) {
+pub fn print_byte(w: &mut impl Write, b: u8, format: Format, colorize: bool) -> io::Result<()> {
let mut color: u8 = b;
if color < 1 {
color = 0x16;
@@ -167,39 +167,43 @@ pub fn print_byte(b: u8, format: Format, colorize: bool) {
if colorize {
// note, for color testing: for (( i = 0; i < 256; i++ )); do echo "$(tput setaf $i)This is ($i) $(tput sgr0)"; done
match format {
- Format::Octal => print!(
+ Format::Octal => write!(
+ w,
"{} ",
ansi_term::Style::new()
.fg(ansi_term::Color::Fixed(color))
.paint(hex_octal(b))
),
- Format::LowerHex => print!(
+ Format::LowerHex => write!(
+ w,
"{} ",
ansi_term::Style::new()
.fg(ansi_term::Color::Fixed(color))
.paint(hex_lower_hex(b))
),
- Format::UpperHex => print!(
+ Format::UpperHex => write!(
+ w,
"{} ",
ansi_term::Style::new()
.fg(ansi_term::Color::Fixed(color))
.paint(hex_upper_hex(b))
),
- Format::Binary => print!(
+ Format::Binary => write!(
+ w,
"{} ",
ansi_term::Style::new()
.fg(ansi_term::Color::Fixed(color))
.paint(hex_binary(b))
),
- _ => print!("unk_fmt "),
+ _ => write!(w, "unk_fmt "),
}
} else {
match format {
- Format::Octal => print!("{} ", hex_octal(b)),
- Format::LowerHex => print!("{} ", hex_lower_hex(b)),
- Format::UpperHex => print!("{} ", hex_upper_hex(b)),
- Format::Binary => print!("{} ", hex_binary(b)),
- _ => print!("unk_fmt "),
+ Format::Octal => write!(w, "{} ", hex_octal(b)),
+ Format::LowerHex => write!(w, "{} ", hex_lower_hex(b)),
+ Format::UpperHex => write!(w, "{} ", hex_upper_hex(b)),
+ Format::Binary => write!(w, "{} ", hex_binary(b)),
+ _ => write!(w, "unk_fmt "),
}
}
}
@@ -234,9 +238,9 @@ pub fn run(matches: ArgMatches) -> Result<(), Box<dyn Error>> {
let mut buf: Box<dyn BufRead> = if is_stdin.unwrap() {
Box::new(BufReader::new(io::stdin()))
} else {
- Box::new(BufReader::new(
- fs::File::open(matches.value_of(ARG_INP).unwrap()).unwrap(),
- ))
+ Box::new(BufReader::new(fs::File::open(
+ matches.value_of(ARG_INP).unwrap(),
+ )?))
};
let mut format_out = Format::LowerHex;
let mut colorize = true;
@@ -246,7 +250,7 @@ pub fn run(matches: ArgMatches) -> Result<(), Box<dyn Error>> {
}
if let Some(length) = matches.value_of(ARG_LEN) {
- truncate_len = length.parse::<u64>().unwrap();
+ truncate_len = length.parse::<u64>()?;
}
if let Some(format) = matches.value_of(ARG_FMT) {
@@ -274,7 +278,7 @@ pub fn run(matches: ArgMatches) -> Result<(), Box<dyn Error>> {
// array output mode is mutually exclusive
if let Some(array) = matches.value_of(ARG_ARR) {
- output_array(array, buf, truncate_len, column_width);
+ output_array(array, buf, truncate_len, column_width)?;
} else {
// Transforms this Read instance to an Iterator over its bytes.
// The returned type implements Iterator where the Item is
@@ -285,15 +289,18 @@ pub fn run(matches: ArgMatches) -> Result<(), Box<dyn Error>> {
let mut ascii_line: Line = Line::new();
let mut offset_counter: u64 = 0x0;
let mut byte_column: u64 = 0x0;
- let page = buf_to_array(&mut buf, truncate_len, column_width).unwrap();
+ let page = buf_to_array(&mut buf, truncate_len, column_width)?;
+
+ let stdout = io::stdout();
+ let mut locked = stdout.lock();
for line in page.body.iter() {
- print_offset(offset_counter);
+ print_offset(&mut locked, offset_counter)?;
for hex in line.hex_body.iter() {
offset_counter += 1;
byte_column += 1;
- print_byte(*hex, format_out, colorize);
+ print_byte(&mut locked, *hex, format_out, colorize)?;
if *hex > 31 && *hex < 127 {
ascii_line.ascii.push(*hex as char);
@@ -303,17 +310,21 @@ pub fn run(matches: ArgMatches) -> Result<(), Box<dyn Error>> {
}
if byte_column < column_width {
- print!("{:<1$}", "", 5 * (column_width - byte_column) as usize);
+ write!(
+ locked,
+ "{:<1$}",
+ "",
+ 5 * (column_width - byte_column) as usize
+ )?;
}
byte_column = 0x0;
let ascii_string: String = ascii_line.ascii.iter().cloned().collect();
ascii_line = Line::new();
- print!("{}", ascii_string); // print ascii string
- println!();
+ writeln!(locked, "{}", ascii_string)?; // print ascii string
}
if true {
- println!(" bytes: {}", page.bytes);
+ writeln!(locked, " bytes: {}", page.bytes)?;
}
}
}
@@ -330,24 +341,18 @@ pub fn is_stdin(matches: ArgMatches) -> Result<bool, Box<dyn Error>> {
dbg!(env::args().len(), matches.args.len());
dbg!(env::args().nth(0).unwrap());
}
- if let Some(nth1) = env::args().nth(1) {
+ if let Some(file) = matches.value_of(ARG_INP) {
if DBG > 0 {
- dbg!(nth1);
+ dbg!(file);
}
- for arg in ARGS.iter() {
- if let Some(index) = matches.index_of(arg) {
- if let 2 = index {
- is_stdin = true;
- }
- }
+ is_stdin = false;
+ } else if let Some(nth1) = env::args().nth(1) {
+ if DBG > 0 {
+ dbg!(nth1);
}
+ is_stdin = ARGS.iter().any(|arg| matches.index_of(arg) == Some(2));
} else if matches.args.is_empty() {
is_stdin = true;
- } else if let Some(file) = matches.value_of(ARG_INP) {
- if DBG > 0 {
- dbg!(file);
- }
- is_stdin = false;
}
if DBG > 0 {
dbg!(is_stdin);
@@ -367,33 +372,41 @@ pub fn output_array(
mut buf: Box<dyn BufRead>,
truncate_len: u64,
column_width: u64,
-) {
+) -> io::Result<()> {
+ let stdout = io::stdout();
+ let mut locked = stdout.lock();
+
let page = buf_to_array(&mut buf, truncate_len, column_width).unwrap();
match array_format {
- "r" => println!("let ARRAY: [u8; {}] = [", page.bytes),
- "c" => println!("unsigned char ARRAY[{}] = {{", page.bytes),
- "g" => println!("a := [{}]byte{{", page.bytes),
- _ => println!("unknown array format"),
+ "r" => writeln!(locked, "let ARRAY: [u8; {}] = [", page.bytes)?,
+ "c" => writeln!(locked, "unsigned char ARRAY[{}] = {{", page.bytes)?,
+ "g" => writeln!(locked, "a := [{}]byte{{", page.bytes)?,
+ _ => writeln!(locked, "unknown array format")?,
}
let mut i: u64 = 0x0;
for line in page.body.iter() {
- print!(" ");
+ write!(locked, " ")?;
for hex in line.hex_body.iter() {
i += 1;
if i == page.bytes && array_format != "g" {
- print!("{}", hex_lower_hex(*hex));
+ write!(locked, "{}", hex_lower_hex(*hex))?;
} else {
- print!("{}, ", hex_lower_hex(*hex));
+ write!(locked, "{}, ", hex_lower_hex(*hex))?;
}
}
- println!();
- }
- match array_format {
- "r" => println!("];"),
- "c" => println!("}};"),
- "g" => println!("}}"),
- _ => println!("unknown array format"),
+ writeln!(locked)?;
}
+
+ writeln!(
+ locked,
+ "{}",
+ match array_format {
+ "r" => "];",
+ "c" => "};",
+ "g" => "}",
+ _ => "unknown array format",
+ }
+ )
}
/// Function wave out.
@@ -433,7 +446,7 @@ pub fn buf_to_array(
let mut page: Page = Page::new();
let mut line: Line = Line::new();
for b in buf.bytes() {
- let b1: u8 = b.unwrap();
+ let b1: u8 = b?;
line.bytes += 1;
page.bytes += 1;
line.hex_body.push(b1);
@@ -495,4 +508,59 @@ mod tests {
assert_eq!(hex_binary(b), "0b11111111");
assert_eq!(hex_binary(b), format!("{:#010b}", b));
}
+ use assert_cmd::Command;
+
+ /// target/debug/hx -ar tests/files/tiny.txt
+ #[test]
+ fn test_cli_arg_order_1() {
+ let mut cmd = Command::cargo_bin("hx").unwrap();
+ let assert = cmd.arg("-ar").arg("tests/files/tiny.txt").assert();
+ assert
+ .success()
+ .code(0)
+ .stdout("let ARRAY: [u8; 3] = [\n 0x69, 0x6c, 0x0a\n];\n");
+ }
+
+ /// target/debug/hx tests/files/tiny.txt -ar
+ #[test]
+ fn test_cli_arg_order_2() {
+ let mut cmd = Command::cargo_bin("hx").unwrap();
+ let assert = cmd.arg("tests/files/tiny.txt").arg("-ar").assert();
+ assert
+ .success()
+ .code(0)
+ .stdout("let ARRAY: [u8; 3] = [\n 0x69, 0x6c, 0x0a\n];\n");
+ }
+
+ /// target/debug/hx --len tests/files/tiny.txt
+ /// error: invalid digit found in string
+ #[test]
+ fn test_cli_missing_param_value() {
+ let mut cmd = Command::cargo_bin("hx").unwrap();
+ let assert = cmd.arg("--len").arg("tests/files/tiny.txt").assert();
+ assert.failure().code(1);
+ }
+
+ #[test]
+ fn test_cli_input_missing_file() {
+ let mut cmd = Command::cargo_bin("hx").unwrap();
+ let assert = cmd.arg("missing-file").assert();
+ assert.failure().code(1);
+ }
+
+ #[test]
+ fn test_cli_input_directory() {
+ let mut cmd = Command::cargo_bin("hx").unwrap();
+ let assert = cmd.arg("src").assert();
+ assert.failure().code(1);
+ }
+
+ #[test]
+ fn test_cli_input_stdin() {
+ let mut cmd = Command::cargo_bin("hx").unwrap();
+ let assert = cmd.arg("-t0").write_stdin("012").assert();
+ assert.success().code(0).stdout(
+ "0x000000: 0x30 0x31 0x32 012\n bytes: 3\n",
+ );
+ }
}
diff --git a/src/main.rs b/src/main.rs
index d008aba..2c19a30 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -85,7 +85,11 @@ fn main() {
process::exit(0);
}
Err(e) => {
- eprintln!("error = \"{}\"", e);
+ eprintln!(
+ "{} {}",
+ ansi_term::Colour::Fixed(9).bold().paint("error:"),
+ e
+ );
process::exit(1);
}
}
diff --git a/tests.sh b/tests.sh
new file mode 100755
index 0000000..b6782cd
--- /dev/null
+++ b/tests.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# param ordering 1
+target/debug/hx -ar tests/files/tiny.txt
+# param ordering 2
+target/debug/hx tests/files/tiny.txt -ar
+# binary output column width 4
+target/debug/hx -c4 -fb tests/files/alphanumeric.txt
+# missing len param
+target/debug/hx --len tests/files/tiny.txt
+# missing file name
+target/debug/hx missing-file
+# simulate broken pipe
+dd if=/dev/random bs=512 count=10 | RUST_BACKTRACE=1 target/debug/hx | head -n 10