193 lines
5.7 KiB
Rust
193 lines
5.7 KiB
Rust
mod version;
|
|
mod hdinfo;
|
|
|
|
fn main()
|
|
{
|
|
let mut filenames=vec!();
|
|
let mut state=parseargs(&mut filenames);
|
|
state.hexdump_filenames_or_stdin(&filenames);
|
|
}
|
|
|
|
fn parseargs(filenames:&mut Vec<String>)->hdinfo::Hdinfo
|
|
{
|
|
let argv:Vec<String>=std::env::args().collect();
|
|
let mut curarg=1;
|
|
let mut state:hdinfo::Hdinfo=hdinfo::Hdinfo::new();
|
|
let helpmsg=format!("hd v{}\n\
|
|
usage: {} [-abh] [-n OFFSET] [-r RADIX] [-w WIDTH] [--help] FILES\n\
|
|
-a Don't display ASCII dump\n\
|
|
-b Don't display binary file offset\n\
|
|
-h, --help Display this help\n\
|
|
-n SIZE Number of bytes to read\n\
|
|
-r RADIX Number base (default: 16)\n\
|
|
-w WIDTH Number of columns for output\n\n\
|
|
SIZE An unsigned integer or a percentage (e.g., 50%)\n\
|
|
RADIX One of: 8, 10, 16",
|
|
version::VERSION,
|
|
argv[0]);
|
|
|
|
// Parse each file
|
|
while curarg < argv.len()
|
|
{
|
|
|
|
// Set width of columns
|
|
if argv[curarg]=="-w"
|
|
{
|
|
if argv.len()>curarg+1
|
|
{
|
|
curarg+=1;
|
|
state.columns=match argv[curarg].parse::<usize>()
|
|
{
|
|
Ok(n) => n,
|
|
Err(_) => 8,
|
|
};
|
|
}
|
|
else
|
|
{
|
|
print!("error: -w requires WIDTH argument\n");
|
|
std::process::exit(1);
|
|
}
|
|
}
|
|
|
|
// Set radix/base for hex dump
|
|
else if argv[curarg]=="-r"
|
|
{
|
|
if argv.len()>curarg+1
|
|
{
|
|
curarg+=1;
|
|
state.radix=match argv[curarg].parse::<usize>()
|
|
{
|
|
Ok(n) => n as u32,
|
|
Err(_) => 16u32,
|
|
};
|
|
if ![2,8,10,16].contains(&state.radix)
|
|
{
|
|
print!("error: unrecognized radix '{}'\n",state.radix);
|
|
std::process::exit(1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
print!("error: -r requires RADIX argument\n");
|
|
std::process::exit(1);
|
|
}
|
|
}
|
|
|
|
// Set number of bytes to read
|
|
else if argv[curarg]=="-n"
|
|
{
|
|
if argv.len()>curarg+1
|
|
{
|
|
curarg+=1;
|
|
|
|
// Set percentage
|
|
if argv[curarg].chars().nth(argv[curarg].len()-1).unwrap()=='%'
|
|
{
|
|
state.percent=match argv[curarg][0..argv[curarg].len()-1].parse::<usize>()
|
|
{
|
|
Ok(n) => n as f32/100.0,
|
|
Err(_) => 1.0,
|
|
};
|
|
}
|
|
|
|
// Set bytes offset
|
|
else
|
|
{
|
|
state.numbytes=match argv[curarg].parse::<usize>()
|
|
{
|
|
Ok(n) => n,
|
|
Err(_) => 0,
|
|
};
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
print!("error: -n requires SIZE argument\n");
|
|
std::process::exit(1);
|
|
}
|
|
}
|
|
|
|
// Options
|
|
else if argv[curarg].chars().nth(0).unwrap()=='-'
|
|
{
|
|
|
|
// Long option
|
|
if argv[curarg].len()>curarg && argv[curarg].chars().nth(1).unwrap()=='-'
|
|
{
|
|
match argv[curarg].as_str()
|
|
{
|
|
|
|
// Display help message
|
|
"--help" =>
|
|
{
|
|
print!("{}\n",helpmsg);
|
|
std::process::exit(0);
|
|
},
|
|
|
|
// Unrecognized option
|
|
_ =>
|
|
{
|
|
print!("error: unrecognized long option '{}'\n",argv[curarg]);
|
|
std::process::exit(1);
|
|
},
|
|
}
|
|
}
|
|
|
|
// Short options
|
|
else
|
|
{
|
|
for i in 1..argv[curarg].len()
|
|
{
|
|
let c=argv[curarg].chars().nth(i).unwrap();
|
|
|
|
match c
|
|
{
|
|
|
|
// Toggle showoffset (display file offset of hexdump)
|
|
'b' =>
|
|
{
|
|
state.showoffset=false;
|
|
},
|
|
|
|
// Toggle showascii (show ascii rendering)
|
|
'a' =>
|
|
{
|
|
state.showascii=false;
|
|
},
|
|
|
|
// Display help message
|
|
'h' =>
|
|
{
|
|
print!("{}\n",helpmsg);
|
|
std::process::exit(0);
|
|
},
|
|
|
|
// Warning for short options with arguments
|
|
'w' | 'n' | 'r' =>
|
|
{
|
|
print!("warning: use -{} on its own\n",
|
|
argv[curarg].chars().nth(i).unwrap());
|
|
},
|
|
|
|
// Unrecognized option
|
|
_ =>
|
|
{
|
|
print!("error: unrecognized short option '{}'\n",c);
|
|
std::process::exit(1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Default options treated as input filenames
|
|
else
|
|
{
|
|
filenames.push(argv[curarg].clone());
|
|
}
|
|
curarg+=1;
|
|
}
|
|
return state;
|
|
}
|