basic functionality works
This commit is contained in:
parent
f8cf93fc92
commit
197ad9dabf
5 changed files with 221 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
target
|
81
Cargo.lock
generated
Normal file
81
Cargo.lock
generated
Normal file
|
@ -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"
|
15
Cargo.toml
Normal file
15
Cargo.toml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[package]
|
||||||
|
name = "timars"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
publish = false
|
||||||
|
authors = ["Christoph J. Scherr <software@cscherr.de>"]
|
||||||
|
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"
|
|
@ -1,2 +1,5 @@
|
||||||
# timars
|
# 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.
|
||||||
|
|
||||||
|
|
121
src/main.rs
Normal file
121
src/main.rs
Normal file
|
@ -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<Self, Self::Err> {
|
||||||
|
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<String> = 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)
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue