diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eb5a316 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..1b63927 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,81 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "timars" +version = "0.1.0" +dependencies = [ + "getopts", + "thiserror", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..3da806e --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "timars" +version = "0.1.0" +edition = "2024" +publish = false +authors = ["Christoph J. Scherr "] +license = "MIT" +readme = "README.md" +homepage = "https://git.cscherr.de/PlexSheep/rs-base" +repository = "https://git.cscherr.de/PlexSheep/rs-base" + + +[dependencies] +getopts = "0.2.21" +thiserror = "2.0.12" diff --git a/README.md b/README.md index f778e06..f56c46c 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ # timars +Timars is two things at once: It lets you calculate time between two clock times, +and it lets you hide some secret beneath an intended binary exploitation. + diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..441b5ab --- /dev/null +++ b/src/main.rs @@ -0,0 +1,121 @@ +use std::fmt::Display; +use std::ops::Sub; +use std::str::FromStr; + +use getopts::Options; +use thiserror::Error; + +const FLAG: &str = "FlÂG{E1nb38V9a3V5e86HzlY27UFAErIP5mA34kES9fbu}"; + +fn options() -> Options { + let mut opts = Options::new(); + + opts.reqopt( + "f", + "from", + "calculate time starting from this time", + "HH:MM", + ); + opts.reqopt("t", "to", "calculate time until this time", "HH:MM"); + + opts.optflag("h", "help", "print this help menu"); + + opts +} + +struct Timestamp { + hour: i8, + minute: i8, +} + +#[derive(Error, Debug)] +enum TimestampParseError { + #[error("Too many or too few separators ':'")] + BadAmountOfSeparators, + #[error("Time numbers t must fullfill 0 < t < 60 (was {0})")] + InvalidTimeNumber(i8), + #[error(transparent)] + ParseInt(#[from] std::num::ParseIntError), +} + +impl Sub for Timestamp { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + if self.minute >= rhs.minute { + Timestamp { + hour: self.hour - rhs.hour, + minute: self.minute - rhs.minute, + } + } else { + Timestamp { + hour: self.hour - rhs.hour - 1, + minute: 60 + self.minute - rhs.minute, + } + } + } +} + +impl Display for Timestamp { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:02}:{:02}", self.hour, self.minute) + } +} + +impl FromStr for Timestamp { + fn from_str(s: &str) -> Result { + let parts: Vec<&str> = s.split(":").collect(); + if parts.len() != 2 { + return Err(TimestampParseError::BadAmountOfSeparators); + } + + let hour: i8 = parts[0].parse()?; + let minute: i8 = parts[1].parse()?; + + if hour > 59 { + return Err(TimestampParseError::InvalidTimeNumber(hour)); + } + if minute > 59 { + return Err(TimestampParseError::InvalidTimeNumber(minute)); + } + + let t = Timestamp { hour, minute }; + Ok(t) + } + + type Err = TimestampParseError; +} + +fn main() { + let args: Vec = std::env::args().collect(); + let program = args[0].clone(); + let opts = options(); + let matches = match opts.parse(&args[1..]) { + Ok(m) => m, + Err(f) => usage(&program, &opts), + }; + let from_time: Timestamp = match matches.opt_str("from").expect("thats required").parse() { + Ok(t) => t, + Err(e) => { + eprintln!("{e}"); + usage(&program, &opts) + } + }; + let to_time: Timestamp = match matches.opt_str("to").expect("thats required").parse() { + Ok(t) => t, + Err(e) => { + eprintln!("{e}"); + usage(&program, &opts) + } + }; + + println!("from\t\t: {from_time}"); + println!("to\t\t: {to_time}"); + println!("difference\t: {}", to_time - from_time) +} + +fn usage(program: &str, opts: &Options) -> ! { + let brief = format!("Usage: {} FILE [options]", program); + print!("{}", opts.usage(&brief)); + std::process::exit(1) +}