generated from PlexSheep/rs-base
parent
4c5f0f446b
commit
5d35851ef6
18
Cargo.toml
18
Cargo.toml
|
@ -1,16 +1,18 @@
|
|||
[package]
|
||||
name = "template"
|
||||
name = "hedu"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
authors = ["Christoph J. Scherr <software@cscherr.de>"]
|
||||
license = "MIT"
|
||||
description = "No description yet"
|
||||
license = "GPL-3.0-or-later"
|
||||
description = "Hex dumping tool written in Rust"
|
||||
readme = "README.md"
|
||||
homepage = "https://git.cscherr.de/PlexSheep/rs-base"
|
||||
repository = "https://git.cscherr.de/PlexSheep/rs-base"
|
||||
keywords = ["template"]
|
||||
|
||||
homepage = "https://git.cscherr.de/PlexSheep/hedu"
|
||||
repository = "https://git.cscherr.de/PlexSheep/hedu"
|
||||
keywords = ["hexdumper"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
libpt = { version = "0.3.11", features = ["log", "bintols"] }
|
||||
clap = { version = "4.4.4", features = ["derive", "help"] }
|
||||
clap-num = { version = "1.0.2" }
|
||||
clap-verbosity-flag = { version = "2.0.1" }
|
||||
|
|
Binary file not shown.
Binary file not shown.
176
src/main.rs
176
src/main.rs
|
@ -1,3 +1,175 @@
|
|||
fn main() {
|
||||
println!("Hello, world!");
|
||||
//! # Executable for the hedu submodule
|
||||
//!
|
||||
//! Dump data to a fancy format.
|
||||
|
||||
//// ATTRIBUTES ////////////////////////////////////////////////////////////////////////////////////
|
||||
// we want docs
|
||||
#![warn(missing_docs)]
|
||||
#![warn(rustdoc::missing_crate_level_docs)]
|
||||
// we want Debug everywhere.
|
||||
#![warn(missing_debug_implementations)]
|
||||
// enable clippy's extra lints, the pedantic version
|
||||
#![warn(clippy::pedantic)]
|
||||
|
||||
//// IMPORTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
use libpt::{bintols::hedu::*, log::*};
|
||||
|
||||
use clap::Parser;
|
||||
use clap_verbosity_flag::{InfoLevel, Verbosity};
|
||||
|
||||
use std::{fs::File, io::IsTerminal, path::PathBuf};
|
||||
|
||||
//// TYPES /////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// CONSTANTS /////////////////////////////////////////////////////////////////////////////////////
|
||||
/// short about section displayed in help
|
||||
const ABOUT_ROOT: &'static str = r##"
|
||||
Dumps data in fancy formats.
|
||||
"##;
|
||||
/// longer about section displayed in help, is combined with [the short help](ABOUT_ROOT)
|
||||
static LONG_ABOUT_ROOT: &'static str = r##"
|
||||
|
||||
libpt is a personal general purpose library, offering this executable, a python module and a
|
||||
dynamic library.
|
||||
"##;
|
||||
|
||||
//// STATICS ///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// MACROS ////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// ENUMS /////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// STRUCTS ///////////////////////////////////////////////////////////////////////////////////////
|
||||
/// defines CLI interface
|
||||
#[derive(Debug, Clone, Parser)]
|
||||
#[command(
|
||||
author,
|
||||
version,
|
||||
about = ABOUT_ROOT,
|
||||
long_about = format!("{}{}", ABOUT_ROOT ,LONG_ABOUT_ROOT),
|
||||
help_template =
|
||||
r#"{about-section}
|
||||
{usage-heading} {usage}
|
||||
{all-args}{tab}
|
||||
|
||||
libpt: {version}
|
||||
Author: {author-with-newline}
|
||||
"#
|
||||
)]
|
||||
pub struct Cli {
|
||||
// clap_verbosity_flag seems to make this a global option implicitly
|
||||
/// set a verbosity, multiple allowed (f.e. -vvv)
|
||||
#[command(flatten)]
|
||||
pub verbose: Verbosity<InfoLevel>,
|
||||
|
||||
/// show additional logging meta data
|
||||
#[arg(long)]
|
||||
pub meta: bool,
|
||||
|
||||
/// show character representation
|
||||
#[arg(short, long)]
|
||||
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 limit: usize,
|
||||
|
||||
/// show identical lines
|
||||
#[arg(short = 'i', long)]
|
||||
pub show_identical: bool,
|
||||
|
||||
/// a data source, probably a file.
|
||||
///
|
||||
/// If left empty or set as "-", the program will read from stdin.
|
||||
// TODO: take many sources #60
|
||||
pub data_source: Vec<String>,
|
||||
}
|
||||
|
||||
//// IMPLEMENTATION ////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// PUBLIC FUNCTIONS //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//// PRIVATE FUNCTIONS /////////////////////////////////////////////////////////////////////////////
|
||||
fn main() {
|
||||
let mut cli = cli_parse();
|
||||
let mut sources: Vec<Box<dyn DataSource>> = Vec::new();
|
||||
if cli.data_source.len() > 0 && cli.data_source[0] != "-" {
|
||||
for data_source in &cli.data_source {
|
||||
let data_source: PathBuf = PathBuf::from(data_source);
|
||||
if data_source.is_dir() {
|
||||
warn!("Not a file {:?}, skipping", data_source);
|
||||
// std::process::exit(1);
|
||||
continue;
|
||||
}
|
||||
trace!("Trying to open '{:?}'", data_source);
|
||||
match File::open(&data_source) {
|
||||
Ok(file) => sources.push(Box::new(file)),
|
||||
Err(err) => {
|
||||
error!("Could not open '{:?}': {err}", data_source);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
}
|
||||
} else {
|
||||
trace!("Trying to open stdin");
|
||||
let stdin = std::io::stdin();
|
||||
if stdin.is_terminal() {
|
||||
warn!("Refusing to dump from interactive terminal");
|
||||
std::process::exit(2)
|
||||
}
|
||||
// just for the little header
|
||||
cli.data_source = Vec::new();
|
||||
cli.data_source.push(format!("stdin"));
|
||||
sources.push(Box::new(stdin));
|
||||
}
|
||||
for (i, source) in sources.iter_mut().enumerate() {
|
||||
let mut config = Hedu::new(cli.chars, cli.skip, cli.show_identical, cli.limit);
|
||||
// FIXME: find a better way to get the file name
|
||||
// Currently, skipped sources make an extra newline here.
|
||||
match config.chars {
|
||||
false => {
|
||||
println!("{:─^59}", format!(" {} ", cli.data_source[i]));
|
||||
}
|
||||
true => {
|
||||
println!("{:─^80}", format!(" {} ", cli.data_source[i]));
|
||||
}
|
||||
}
|
||||
match config.dump(&mut **source) {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
error!("Could not dump data of file: {err}");
|
||||
std::process::exit(3);
|
||||
}
|
||||
}
|
||||
if i < cli.data_source.len() - 1 {
|
||||
config.newline();
|
||||
}
|
||||
}
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
fn cli_parse() -> Cli {
|
||||
let cli = Cli::parse();
|
||||
let ll: Level = match cli.verbose.log_level().unwrap().as_str() {
|
||||
"TRACE" => Level::TRACE,
|
||||
"DEBUG" => Level::DEBUG,
|
||||
"INFO" => Level::INFO,
|
||||
"WARN" => Level::WARN,
|
||||
"ERROR" => Level::ERROR,
|
||||
_ => {
|
||||
unreachable!();
|
||||
}
|
||||
};
|
||||
if cli.meta {
|
||||
Logger::init(None, Some(ll), false).expect("could not initialize Logger");
|
||||
} else {
|
||||
// less verbose version
|
||||
Logger::init_mini(Some(ll)).expect("could not initialize Logger");
|
||||
}
|
||||
return cli;
|
||||
}
|
||||
|
||||
|
|
Reference in New Issue