generated from PlexSheep/baserepo
more configs
Cargo Check, Format, Fix and Test / cargo CI (push) Successful in 2m41s
Details
Cargo Check, Format, Fix and Test / cargo CI (push) Successful in 2m41s
Details
can't detect dups like this dedup lines
This commit is contained in:
parent
b2435f3963
commit
441669a2c3
|
@ -13,7 +13,7 @@ members = [
|
||||||
default-members = [".", "members/libpt-bin", "members/libpt-core"]
|
default-members = [".", "members/libpt-bin", "members/libpt-core"]
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
publish = true
|
publish = true
|
||||||
version = "0.2.0"
|
version = "0.2.3"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["Christoph J. Scherr <software@cscherr.de>"]
|
authors = ["Christoph J. Scherr <software@cscherr.de>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -20,7 +20,7 @@ use clap_verbosity_flag::{InfoLevel, Verbosity};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{BufRead, BufReader, IsTerminal},
|
io::{Seek, IsTerminal},
|
||||||
};
|
};
|
||||||
|
|
||||||
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
|
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -67,13 +67,25 @@ pub struct Cli {
|
||||||
pub verbose: Verbosity<InfoLevel>,
|
pub verbose: Verbosity<InfoLevel>,
|
||||||
|
|
||||||
/// show additional logging meta data
|
/// show additional logging meta data
|
||||||
#[arg(short, long, global = true)]
|
#[arg(long)]
|
||||||
pub log_meta: bool,
|
pub meta: bool,
|
||||||
|
|
||||||
/// show character representation
|
/// show character representation
|
||||||
#[arg(short, long, global = true)]
|
#[arg(short, long)]
|
||||||
pub chars: bool,
|
pub chars: bool,
|
||||||
|
|
||||||
|
/// skip first N bytes
|
||||||
|
#[arg(short, long, default_value_t = 0)]
|
||||||
|
pub skip: usize,
|
||||||
|
|
||||||
|
/// only interpret N bytes (end after N)
|
||||||
|
#[arg(short, long, default_value_t = 0)]
|
||||||
|
pub len: usize,
|
||||||
|
|
||||||
|
/// show identical lines
|
||||||
|
#[arg(short = 'i', long)]
|
||||||
|
pub show_identical: bool,
|
||||||
|
|
||||||
/// a data source, probably a file.
|
/// a data source, probably a file.
|
||||||
///
|
///
|
||||||
/// If left empty or set as "-", the program will read from stdin.
|
/// If left empty or set as "-", the program will read from stdin.
|
||||||
|
@ -87,12 +99,12 @@ pub struct Cli {
|
||||||
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
||||||
fn main() {
|
fn main() {
|
||||||
let cli = cli_parse();
|
let cli = cli_parse();
|
||||||
let source: Box<dyn BufRead>;
|
let mut source: Box<dyn DataSource>;
|
||||||
if cli.data_source.is_some() && cli.data_source.clone().is_some_and(|val| val != "-") {
|
if cli.data_source.is_some() && cli.data_source.clone().is_some_and(|val| val != "-") {
|
||||||
let data_source = cli.data_source.unwrap();
|
let data_source = cli.data_source.unwrap();
|
||||||
debug!("Trying to open '{}'", data_source);
|
debug!("Trying to open '{}'", data_source);
|
||||||
source = match File::open(&data_source) {
|
source = match File::open(&data_source) {
|
||||||
Ok(file) => Box::new(BufReader::new(file)),
|
Ok(file) => Box::new(file),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("Could not open file '{}': {err}", data_source);
|
error!("Could not open file '{}': {err}", data_source);
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
|
@ -105,9 +117,18 @@ fn main() {
|
||||||
warn!("Refusing to dump from interactive terminal");
|
warn!("Refusing to dump from interactive terminal");
|
||||||
std::process::exit(2)
|
std::process::exit(2)
|
||||||
}
|
}
|
||||||
source = Box::new(BufReader::new(stdin));
|
source = Box::new(stdin);
|
||||||
}
|
}
|
||||||
match dump(BufReader::new(source), cli.chars) {
|
|
||||||
|
match dump(
|
||||||
|
&mut *source,
|
||||||
|
DumpConfig {
|
||||||
|
chars: cli.chars,
|
||||||
|
skip: cli.skip,
|
||||||
|
show_identical: cli.show_identical,
|
||||||
|
len: cli.len,
|
||||||
|
},
|
||||||
|
) {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("Could not dump data of file: {err}");
|
error!("Could not dump data of file: {err}");
|
||||||
|
@ -128,7 +149,7 @@ fn cli_parse() -> Cli {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if cli.log_meta {
|
if cli.meta {
|
||||||
Logger::init(None, Some(ll)).expect("could not initialize Logger");
|
Logger::init(None, Some(ll)).expect("could not initialize Logger");
|
||||||
} else {
|
} else {
|
||||||
// less verbose version
|
// less verbose version
|
||||||
|
|
|
@ -18,3 +18,4 @@ categories.workspace = true
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
libpt-log = {path = "../libpt-log" }
|
libpt-log = {path = "../libpt-log" }
|
||||||
|
libpt-bintols = {path = "../libpt-bintols" }
|
||||||
|
|
|
@ -6,40 +6,69 @@
|
||||||
//! This crate is currently empty.
|
//! This crate is currently empty.
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use libpt_log::{error, trace};
|
use libpt_log::{error, trace, warn, info};
|
||||||
use std::io::{prelude::*, BufReader};
|
use libpt_bintols::display::{bytes_to_bin, humanbytes};
|
||||||
|
use std::io::{prelude::*, BufReader, Read, SeekFrom};
|
||||||
|
|
||||||
const BYTES_PER_LINE: usize = 16;
|
const BYTES_PER_LINE: usize = 16;
|
||||||
const LINE_SEP_HORIZ: char = '─';
|
const LINE_SEP_HORIZ: char = '─';
|
||||||
const LINE_SEP_VERT: char = '│';
|
const LINE_SEP_VERT: char = '│';
|
||||||
|
|
||||||
pub fn dump<T>(mut data: BufReader<T>, chars: bool) -> Result<()>
|
pub struct DumpConfig {
|
||||||
where
|
pub chars: bool,
|
||||||
T: Read,
|
pub skip: usize,
|
||||||
{
|
pub show_identical: bool,
|
||||||
let mut buf: [u8; BYTES_PER_LINE] = [0; BYTES_PER_LINE];
|
pub len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait DataSource: Read {
|
||||||
|
fn skip(&mut self, length: usize) -> std::io::Result<()>;
|
||||||
|
}
|
||||||
|
impl DataSource for std::io::Stdin {
|
||||||
|
fn skip(&mut self, _length: usize) -> std::io::Result<()> {
|
||||||
|
warn!("can't skip bytes for the stdin!");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl DataSource for std::fs::File {
|
||||||
|
fn skip(&mut self, length: usize) -> std::io::Result<()> {
|
||||||
|
self.seek(SeekFrom::Current(length as i64))?;
|
||||||
|
// returns the new position from the start, we don't need it here.
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dump(data: &mut dyn DataSource, config: DumpConfig) -> Result<()> {
|
||||||
|
// skip a given number of bytes
|
||||||
|
if config.skip > 0 {
|
||||||
|
|
||||||
|
data.skip(config.skip)?;
|
||||||
|
info!("Skipped {}", humanbytes(config.skip));
|
||||||
|
}
|
||||||
|
let mut buf: [[u8; BYTES_PER_LINE]; 2] = [[0; BYTES_PER_LINE]; 2];
|
||||||
|
let mut alt_buf = 0usize;
|
||||||
let mut line_counter: usize = 0;
|
let mut line_counter: usize = 0;
|
||||||
let mut len: usize;
|
let mut len: usize;
|
||||||
// print the head
|
// print the head
|
||||||
print!("LINE IDX {LINE_SEP_VERT} DATA AS HEX");
|
print!("LINE IDX {LINE_SEP_VERT} DATA AS HEX");
|
||||||
if chars {
|
if config.chars {
|
||||||
print!("{:width$} {LINE_SEP_VERT} FOO", "", width = 37);
|
print!("{:width$} {LINE_SEP_VERT} FOO", "", width = 37);
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
if chars {
|
if config.chars {
|
||||||
println!("{}", format!("{LINE_SEP_HORIZ}").repeat(78));
|
println!("{}", format!("{LINE_SEP_HORIZ}").repeat(80));
|
||||||
} else {
|
} else {
|
||||||
println!("{}", format!("{LINE_SEP_HORIZ}").repeat(59));
|
println!("{}", format!("{LINE_SEP_HORIZ}").repeat(59));
|
||||||
}
|
}
|
||||||
// data dump loop
|
// data dump loop
|
||||||
len = rd_data(&mut data, &mut buf).unwrap();
|
len = rd_data(data, &mut buf, &mut alt_buf).unwrap();
|
||||||
while len > 0 {
|
while len > 0 {
|
||||||
print!("{:08X} {LINE_SEP_VERT} ", line_counter);
|
print!("{:08X} {LINE_SEP_VERT} ", line_counter);
|
||||||
for i in 0..len {
|
for i in 0..len {
|
||||||
if i as usize % BYTES_PER_LINE == BYTES_PER_LINE / 2 {
|
if i as usize % BYTES_PER_LINE == BYTES_PER_LINE / 2 {
|
||||||
print!(" ");
|
print!(" ");
|
||||||
}
|
}
|
||||||
print!("{:02X} ", buf[i]);
|
print!("{:02X} ", buf[alt_buf][i]);
|
||||||
}
|
}
|
||||||
if len == BYTES_PER_LINE / 2 {
|
if len == BYTES_PER_LINE / 2 {
|
||||||
print!(" ")
|
print!(" ")
|
||||||
|
@ -50,15 +79,31 @@ where
|
||||||
}
|
}
|
||||||
print!(" ");
|
print!(" ");
|
||||||
}
|
}
|
||||||
if chars {
|
if config.chars {
|
||||||
print!("{LINE_SEP_VERT} ");
|
print!("{LINE_SEP_VERT} |");
|
||||||
for i in 0..len {
|
for i in 0..len {
|
||||||
print!("{}", mask_chars(buf[i] as char));
|
print!("{}", mask_chars(buf[alt_buf][i] as char));
|
||||||
}
|
}
|
||||||
|
print!("|");
|
||||||
}
|
}
|
||||||
line_counter += 1;
|
line_counter += 1;
|
||||||
println!();
|
println!();
|
||||||
len = rd_data(&mut data, &mut buf).unwrap();
|
len = rd_data(data, &mut buf, &mut alt_buf).unwrap();
|
||||||
|
if buf[0] == buf[1] && len == BYTES_PER_LINE && !config.show_identical {
|
||||||
|
trace!(buf = format!("{:?}", buf), "found a duplicating line");
|
||||||
|
let start_line = line_counter;
|
||||||
|
while buf[0] == buf[1] && len == BYTES_PER_LINE {
|
||||||
|
len = rd_data(data, &mut buf, &mut alt_buf).unwrap();
|
||||||
|
line_counter += 1;
|
||||||
|
}
|
||||||
|
println!(
|
||||||
|
"^^^^^^^^ {LINE_SEP_VERT} (repeats {} lines)",
|
||||||
|
line_counter - start_line
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// switch to the second half of the buf, the original half is stored the old buffer
|
||||||
|
// We detect duplicate lines with this
|
||||||
|
alt_buf ^= 1; // toggle the alt buf
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -77,12 +122,15 @@ fn mask_chars(c: char) -> char {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rd_data<T>(data: &mut BufReader<T>, mut buf: &mut [u8]) -> Result<usize>
|
fn rd_data(
|
||||||
where
|
data: &mut dyn DataSource,
|
||||||
T: Read,
|
buf: &mut [[u8; BYTES_PER_LINE]; 2],
|
||||||
{
|
alt_buf: &mut usize,
|
||||||
match data.read(&mut buf) {
|
) -> Result<usize> {
|
||||||
Ok(len) => Ok(len),
|
match data.read(&mut buf[*alt_buf]) {
|
||||||
|
Ok(len) => {
|
||||||
|
return Ok(len);
|
||||||
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!("error while reading data: {err}");
|
error!("error while reading data: {err}");
|
||||||
bail!(err)
|
bail!(err)
|
||||||
|
|
Reference in New Issue