forked from bonsai/harakit
106 lines
2.9 KiB
Rust
106 lines
2.9 KiB
Rust
/*
|
||
* Copyright (c) 2023–2024 DTB <trinity@trinity.moe>
|
||
* Copyright (c) 2024 Emma Tebibyte <emma@tebibyte.media>
|
||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||
*
|
||
* This program is free software: you can redistribute it and/or modify it under
|
||
* the terms of the GNU Affero General Public License as published by the Free
|
||
* Software Foundation, either version 3 of the License, or (at your option) any
|
||
* later version.
|
||
*
|
||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||
* details.
|
||
*
|
||
* You should have received a copy of the GNU Affero General Public License
|
||
* along with this program. If not, see https://www.gnu.org/licenses/.
|
||
*/
|
||
|
||
use std::{
|
||
env::args,
|
||
process::ExitCode
|
||
};
|
||
|
||
extern crate getopt;
|
||
extern crate sysexits;
|
||
|
||
use getopt::GetOpt;
|
||
use sysexits::{ EX_DATAERR, EX_USAGE };
|
||
|
||
#[cfg(target_os="openbsd")] use sysexits::EX_OSERR;
|
||
#[cfg(target_os="openbsd")] extern crate openbsd;
|
||
#[cfg(target_os="openbsd")] extern crate strerror;
|
||
#[cfg(target_os="openbsd")] use openbsd::{ Promises, pledge, unveil };
|
||
#[cfg(target_os="openbsd")] use strerror::StrError;
|
||
|
||
fn err(argv0: &String, e: String, code: u8) -> ExitCode {
|
||
eprintln!("{}: {}", argv0, e);
|
||
ExitCode::from(code)
|
||
}
|
||
|
||
fn usage(argv0: &String) -> ExitCode {
|
||
eprintln!("Usage: {} [-egl] integer integer...", argv0);
|
||
ExitCode::from(EX_USAGE)
|
||
}
|
||
|
||
fn main() -> ExitCode {
|
||
let argv = args().collect::<Vec<String>>();
|
||
|
||
#[cfg(target_os="openbsd")] {
|
||
let promises = Promises::new("stdio unveil");
|
||
if let Err(e) = pledge(Some(promises), Some(Promises::default())) {
|
||
return err(&argv[0], e.strerror(), EX_OSERR);
|
||
}
|
||
|
||
if let Err(e) = unveil(None, None) {
|
||
return err(&argv[0], e.strerror(), EX_OSERR);
|
||
}
|
||
}
|
||
|
||
let mut e = false; /* args can be == */
|
||
let mut g = false; /* args can be > */
|
||
let mut l = false; /* args can be < */
|
||
let mut optind = 0;
|
||
|
||
if argv.len() < 3 { return usage(&argv[0]); }
|
||
|
||
while let Some(opt) = argv.getopt("egl") {
|
||
match opt.opt() {
|
||
Ok("e") => e = true,
|
||
Ok("g") => g = true,
|
||
Ok("l") => l = true,
|
||
_ => return usage(&argv[0]),
|
||
}
|
||
optind = opt.ind();
|
||
}
|
||
|
||
if !e & !g & !l { return usage(&argv[0]); }
|
||
|
||
if argv.len() - optind < 2 /* see usage */ { return usage(&argv[0]); }
|
||
|
||
let mut prev: Option<usize> = None; /* no previous operand */
|
||
let mut currn: usize;
|
||
|
||
for arg in argv.iter().skip(optind) { /* iterate operands */
|
||
match arg.parse::<usize>() { /* parse current operand */
|
||
Ok(n) => currn = n,
|
||
Err(e) => {
|
||
let error = arg.to_owned() + ": " + &e.to_string();
|
||
return err(&argv[0], error, EX_DATAERR);
|
||
}
|
||
}
|
||
|
||
if let Some(prevn) = prev { /* if there was a previous opr., test */
|
||
if (!e && prevn == currn)
|
||
|| (!g && prevn > currn)
|
||
|| (!l && prevn < currn)
|
||
{ return ExitCode::FAILURE; }
|
||
}
|
||
|
||
prev = Some(currn); /* there is a previous operand */
|
||
}
|
||
|
||
ExitCode::SUCCESS
|
||
}
|