diff options
author | Julian Sitkevich <sitkevij@gmail.com> | 2020-04-20 22:15:40 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-20 22:15:40 -0700 |
commit | 8d531a39df1b63f4c700273b8d1a4322393f121d (patch) | |
tree | dcbccca4d2e8faec3b105e347bf5cd6bac16f1cd /src/lib.rs | |
parent | 66f0a6dab366c5d8f143fcaf3dcd8ec9edde0479 (diff) | |
parent | dcfebef40ffc79192f2fa93dc71c54a4b3e2a083 (diff) |
Merge pull request #18 from sitkevij/feature/stdin-supportv0.3.0
Feature/stdin support
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 239 |
1 files changed, 159 insertions, 80 deletions
@@ -1,4 +1,5 @@ #![deny( + dead_code, missing_docs, missing_debug_implementations, missing_copy_implementations, @@ -9,18 +10,41 @@ unused_import_braces, unused_qualifications )] -// #![allow(dead_code)] //! general hex lib extern crate ansi_term; extern crate clap; use clap::ArgMatches; +use std::env; +use std::error::Error; use std::f64; use std::fs; -use std::fs::File; use std::io::BufReader; -use std::io::Read; +use std::io::{self, BufRead, Read}; + +/// arg cols +pub const ARG_COL: &str = "cols"; +/// arg len +pub const ARG_LEN: &str = "len"; +/// arg format +pub const ARG_FMT: &str = "format"; +/// arg INPUTFILE +pub const ARG_INP: &str = "INPUTFILE"; +/// arg color +pub const ARG_CLR: &str = "color"; +/// arg array +pub const ARG_ARR: &str = "array"; +/// arg func +pub const ARG_FNC: &str = "func"; +/// arg places +pub const ARG_PLC: &str = "places"; + +const ARGS: [&str; 8] = [ + ARG_COL, ARG_LEN, ARG_FMT, ARG_INP, ARG_CLR, ARG_ARR, ARG_FNC, ARG_PLC, +]; + +const DBG: u8 = 0x0; /// nothing ⇒ Display /// ? ⇒ Debug @@ -180,29 +204,9 @@ pub fn print_byte(b: u8, format: Format, colorize: bool) { } } -/// Function wave out. -/// # Arguments -/// -/// * `len` - Wave length. -/// * `places` - Number of decimal places for function wave floats. -pub fn func_out(len: u64, places: usize) { - for y in 0..len { - let y_float: f64 = y as f64; - let len_float: f64 = len as f64; - let x: f64 = (((y_float / len_float) * f64::consts::PI) / 2.0).sin(); - let formatted_number = format!("{:.*}", places, x); - print!("{}", formatted_number); - print!(","); - if (y % 10) == 9 { - println!(); - } - } - println!(); -} - /// In most hex editor applications, the data of the computer file is -/// represented as hexadecimal values grouped in 4 groups of 4 bytes -/// (or two groups of 8 bytes), followed by one group of 16 printable ASCII +/// represented as hexadecimal values grouped in 4 groups of 4 bytes (or +/// two groups of 8 bytes), followed by one group of 16 printable ASCII /// characters which correspond to each pair of hex values (each byte). /// Non-printable ASCII characters (e.g., Bell) and characters that would take /// more than one character space (e.g., tab) are typically represented by a @@ -211,30 +215,41 @@ pub fn func_out(len: u64, places: usize) { /// # Arguments /// /// * `matches` - Argument matches from command line. -pub fn run(matches: ArgMatches) -> Result<(), Box<::std::error::Error>> { +pub fn run(matches: ArgMatches) -> Result<(), Box<dyn Error>> { let mut column_width: u64 = 10; + let mut truncate_len: u64 = 0x0; if let Some(len) = matches.value_of("func") { let mut p: usize = 4; if let Some(places) = matches.value_of("places") { p = places.parse::<usize>().unwrap(); } - func_out(len.parse::<u64>().unwrap(), p); - } else if let Some(file) = matches.value_of("INPUTFILE") { - let f = File::open(file).unwrap(); - let mut buf_len = fs::metadata(file)?.len(); - let mut buf = BufReader::new(f); + output_function(len.parse::<u64>().unwrap(), p); + } else { + // cases: + // $ cat Cargo.toml | target/debug/hx + // $ cat Cargo.toml | target/debug/hx -a r + // $ target/debug/hx Cargo.toml + // $ target/debug/hx Cargo.toml -a r + let is_stdin = is_stdin(matches.clone()); + 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(), + )) + }; let mut format_out = Format::LowerHex; let mut colorize = true; - if let Some(columns) = matches.value_of("cols") { + if let Some(columns) = matches.value_of(ARG_COL) { column_width = columns.parse::<u64>().unwrap(); //turbofish } - if let Some(length) = matches.value_of("len") { - buf_len = length.parse::<u64>().unwrap(); + if let Some(length) = matches.value_of(ARG_LEN) { + truncate_len = length.parse::<u64>().unwrap(); } - if let Some(format) = matches.value_of("format") { + if let Some(format) = matches.value_of(ARG_FMT) { // o, x, X, p, b, e, E match format { "o" => format_out = Format::Octal, @@ -248,7 +263,7 @@ pub fn run(matches: ArgMatches) -> Result<(), Box<::std::error::Error>> { } } - if let Some(color) = matches.value_of("color") { + if let Some(color) = matches.value_of(ARG_CLR) { let color_v = color.parse::<u8>().unwrap(); if color_v == 1 { colorize = true; @@ -257,54 +272,21 @@ pub fn run(matches: ArgMatches) -> Result<(), Box<::std::error::Error>> { } } - match matches.occurrences_of("v") { - 0 => print!(""), - 1 => println!("verbose 1"), - 2 => println!("verbose 2"), - 3 | _ => println!("verbose max"), - } - // array output mode is mutually exclusive - if let Some(array) = matches.value_of("array") { - let mut array_format = array; - let mut page = buf_to_array(&mut buf, buf_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"), - } - - let mut i: u64 = 0x0; - for line in page.body.iter() { - print!(" "); - for hex in line.hex_body.iter() { - i += 1; - if i == buf_len && array_format != "g" { - print!("{}", hex_lower_hex(*hex)); - } else { - print!("{}, ", hex_lower_hex(*hex)); - } - } - println!(); - } - match array_format { - "r" => println!("];"), - "c" => println!("}};"), - "g" => println!("}}"), - _ => println!("unknown array format"), - } + if let Some(array) = matches.value_of(ARG_ARR) { + 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 // Result<u8, R::Err>. The yielded item is Ok if a byte was - // successfully read and Err otherwise for I/O errors. EOF is mapped - // to returning None from this iterator. + // successfully read and Err otherwise for I/O errors. EOF is + // mapped to returning None from this iterator. // (https://doc.rust-lang.org/1.16.0/std/io/trait.Read.html#method.bytes) let mut ascii_line: Line = Line::new(); let mut offset_counter: u64 = 0x0; let mut byte_column: u64 = 0x0; - let mut page = buf_to_array(&mut buf, buf_len, column_width).unwrap(); + let page = buf_to_array(&mut buf, truncate_len, column_width).unwrap(); + for line in page.body.iter() { print_offset(offset_counter); @@ -338,18 +320,114 @@ pub fn run(matches: ArgMatches) -> Result<(), Box<::std::error::Error>> { Ok(()) } +/// Detect stdin, file path and/or parameters. +/// # Arguments +/// +/// * `matches` - argument matches. +pub fn is_stdin(matches: ArgMatches) -> Result<bool, Box<dyn Error>> { + let mut is_stdin = false; + if DBG > 0 { + dbg!(env::args().len(), matches.args.len()); + dbg!(env::args().nth(0).unwrap()); + } + if let Some(nth1) = env::args().nth(1) { + if DBG > 0 { + dbg!(nth1); + } + for arg in ARGS.iter() { + if let Some(index) = matches.index_of(arg) { + if let 2 = index { + is_stdin = true; + } + } + } + } 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); + } + Ok(is_stdin) +} + +/// Output source code array format. +/// # Arguments +/// +/// * `array_format` - array format, rust (r), C (c), golang (g). +/// * `buf` - BufRead. +/// * `truncate_len` - truncate to length. +/// * `column_width` - column width. +pub fn output_array( + array_format: &str, + mut buf: Box<dyn BufRead>, + truncate_len: u64, + column_width: u64, +) { + 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"), + } + let mut i: u64 = 0x0; + for line in page.body.iter() { + print!(" "); + for hex in line.hex_body.iter() { + i += 1; + if i == page.bytes && array_format != "g" { + print!("{}", hex_lower_hex(*hex)); + } else { + print!("{}, ", hex_lower_hex(*hex)); + } + } + println!(); + } + match array_format { + "r" => println!("];"), + "c" => println!("}};"), + "g" => println!("}}"), + _ => println!("unknown array format"), + } +} + +/// Function wave out. +/// # Arguments +/// +/// * `len` - Wave length. +/// * `places` - Number of decimal places for function wave floats. +pub fn output_function(len: u64, places: usize) { + for y in 0..len { + let y_float: f64 = y as f64; + let len_float: f64 = len as f64; + let x: f64 = (((y_float / len_float) * f64::consts::PI) / 2.0).sin(); + let formatted_number = format!("{:.*}", places, x); + print!("{}", formatted_number); + print!(","); + if (y % 10) == 9 { + println!(); + } + } + println!(); +} + /// Buffer to array. /// /// # Arguments /// /// * `buf` - Buffer to be read. -/// * `buf_len` - Buffer length. +/// * `buf_len` - force buffer length. /// * `column_width` - column width for output. pub fn buf_to_array( - buf: &mut Read, + buf: &mut dyn Read, buf_len: u64, column_width: u64, -) -> Result<Page, Box<::std::error::Error>> { +) -> Result<Page, Box<dyn ::std::error::Error>> { let mut column_count: u64 = 0x0; let max_array_size: u16 = <u16>::max_value(); // 2^16; let mut page: Page = Page::new(); @@ -366,11 +444,12 @@ pub fn buf_to_array( line = Line::new(); column_count = 0; } - if page.bytes == buf_len || u64::from(max_array_size) == buf_len { - page.body.push(line); + + if buf_len > 0 && (page.bytes == buf_len || u64::from(max_array_size) == buf_len) { break; } } + page.body.push(line); Ok(page) } |