use crate::IoContext;
use clap::Parser;
use std::ffi::OsString;
use std::io::Write;
#[derive(Parser)]
#[command(name = "seq", about = "Print a sequence of numbers")]
pub struct Args {
#[arg()]
pub first: Option<f64>,
#[arg()]
pub increment: Option<f64>,
#[arg()]
pub last: Option<f64>,
}
pub fn execute<I, T>(args: I) -> Result<(), String>
where
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
{
execute_with_context(args, &mut IoContext::default())
}
pub fn execute_with_context<I, T>(args: I, ctx: &mut IoContext) -> Result<(), String>
where
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
{
let raw_args: Vec<String> = args
.into_iter()
.map(|a| a.into().to_string_lossy().into_owned())
.collect();
let positional: Vec<&str> = raw_args
.iter()
.skip(1) .filter(|a| !a.starts_with('-') || a.parse::<f64>().is_ok())
.map(|s| s.as_str())
.collect();
let (first, increment, last): (f64, f64, Option<f64>) = match positional.len() {
0 => (1.0, 1.0, None), 1 => {
let val = positional[0]
.parse::<f64>()
.map_err(|_| format!("seq: invalid argument: '{}'", positional[0]))?;
(1.0, 1.0, Some(val))
}
2 => {
let f = positional[0]
.parse::<f64>()
.map_err(|_| format!("seq: invalid argument: '{}'", positional[0]))?;
let l = positional[1]
.parse::<f64>()
.map_err(|_| format!("seq: invalid argument: '{}'", positional[1]))?;
(f, 1.0, Some(l))
}
_ => {
let f = positional[0]
.parse::<f64>()
.map_err(|_| format!("seq: invalid argument: '{}'", positional[0]))?;
let inc = positional[1]
.parse::<f64>()
.map_err(|_| format!("seq: invalid argument: '{}'", positional[1]))?;
let l = positional[2]
.parse::<f64>()
.map_err(|_| format!("seq: invalid argument: '{}'", positional[2]))?;
(f, inc, Some(l))
}
};
if increment == 0.0 {
return Err("seq: zero increment".to_string());
}
let mut current = first;
loop {
if ctx.cancel_token.is_cancelled() {
return Err("Interrupted".to_string());
}
if let Some(last_val) = last {
if increment > 0.0 && current > last_val {
break;
}
if increment < 0.0 && current < last_val {
break;
}
}
let display = if current == current.floor() && current.abs() < 1e15 {
format!("{}", current as i64)
} else {
format!("{}", current)
};
if writeln!(ctx.stdout, "{}", display).is_err() {
break; }
current += increment;
}
Ok(())
}