use clap::Parser;
use std::net::IpAddr;
use std::ops::RangeInclusive;
pub const PORT_RANGE: RangeInclusive<u16> = 1..=65535;
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
pub struct Cli {
pub addr: IpAddr,
#[arg(value_parser = port_in_range, conflicts_with("common_ports"))]
pub ports: Option<(u16, u16)>,
#[arg(short, long, conflicts_with("ports"))]
pub common_ports: bool,
#[arg(short, long, conflicts_with("greppable"))]
pub verbose: bool,
#[arg(short, long)]
pub sequential: bool,
#[arg(short, long, conflicts_with("verbose"))]
pub greppable: bool,
}
impl Cli {
pub fn get_ports(&self) -> (u16, u16) {
self.ports.unwrap_or((0, 65535))
}
}
fn port_in_range(s: &str) -> Result<(u16, u16), String> {
if s.split_once('-').is_none() {
return Err("port range missing hyphen, must be in start-end format, Ex: 1-16".into());
}
let (start, end) = s.split_once('-').unwrap();
if start > end {
return Err("ending port number range should be higher than the starting number".into());
}
if PORT_RANGE.contains(&start.parse().unwrap()) && PORT_RANGE.contains(&end.parse().unwrap()) {
Ok((start.parse().unwrap(), end.parse().unwrap()))
} else {
Err(format!(
"port not in range {}-{}",
PORT_RANGE.start(),
PORT_RANGE.end()
))
}
}