142 lines
3.0 KiB
Rust
142 lines
3.0 KiB
Rust
/*
|
|
* Copyright (c) 2023 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,
|
|
ffi::OsStr,
|
|
fs::{ read, read_dir },
|
|
path::{ Path, PathBuf },
|
|
process::exit,
|
|
};
|
|
|
|
use arg::Args;
|
|
use nanorand::{ WyRand, Rng };
|
|
|
|
const F_PATH: &str = "/usr/share/fortune";
|
|
|
|
#[derive(Args, Debug)]
|
|
struct Arguments {
|
|
_argv0: String,
|
|
|
|
#[arg(short = "c",)]
|
|
c: bool,
|
|
|
|
#[arg(short = "f")]
|
|
f: bool,
|
|
|
|
cookies: Vec<String>,
|
|
}
|
|
|
|
fn get_cookies(cookies: Option<Vec<String>>) -> Option<Vec<PathBuf>> {
|
|
let list = match read_dir(Path::new(F_PATH)) {
|
|
Ok(path) => path,
|
|
Err(_) => return None,
|
|
};
|
|
|
|
let mut out = list.map(|x| { x.unwrap().path() }).collect::<Vec<PathBuf>>();
|
|
|
|
match cookies {
|
|
Some(cookies) => {
|
|
out.clear();
|
|
for cookie in cookies.iter() {
|
|
out.push(PathBuf::from(format!("{}/{}", F_PATH, cookie)));
|
|
}
|
|
},
|
|
None => {},
|
|
};
|
|
|
|
out.retain(|x| {
|
|
let ft = match x.metadata() {
|
|
Ok(file) => file.is_file(),
|
|
Err(_) => false,
|
|
};
|
|
|
|
x.extension() != Some(OsStr::new("dat")) && ft
|
|
});
|
|
|
|
Some(out)
|
|
}
|
|
|
|
fn tell_fortune(fortunes: String) -> String {
|
|
let parsed = fortunes
|
|
.split('%')
|
|
.collect::<Vec<&str>>();
|
|
|
|
let mut rnd = WyRand::new();
|
|
let fortune = parsed
|
|
.get(rnd.generate_range(0_usize..=parsed.len()))
|
|
.unwrap()
|
|
.trim()
|
|
.to_string();
|
|
|
|
fortune
|
|
}
|
|
|
|
fn main() {
|
|
let argv = args().collect::<Vec<String>>();
|
|
|
|
let opts = match Arguments::from_args(
|
|
argv.clone().iter().map(|x| x.as_str())
|
|
) {
|
|
Ok(args) => args,
|
|
Err(_) => {
|
|
eprintln!("Usage: {} (-cf)", argv[0]);
|
|
exit(1);
|
|
},
|
|
};
|
|
|
|
let selections: Option<Vec<String>>;
|
|
|
|
if opts.cookies.is_empty() { selections = None; }
|
|
else { selections = Some(opts.cookies); }
|
|
|
|
let cookies = match get_cookies(selections) {
|
|
Some(fortunes) => fortunes,
|
|
None => {
|
|
eprintln!("{}: No fortune cookies installed.", argv[0]);
|
|
exit(1);
|
|
},
|
|
};
|
|
|
|
if opts.f {
|
|
for file in &cookies {
|
|
println!("{}", file.file_name().unwrap().to_str().unwrap());
|
|
}
|
|
exit(0);
|
|
}
|
|
|
|
let mut rnd = WyRand::new();
|
|
let cookie = &cookies[
|
|
rnd.generate_range(0_usize..cookies.len())
|
|
];
|
|
|
|
if opts.c { println!("{:?}\n%", cookie.as_os_str()); }
|
|
|
|
let fortune = match read(cookie) {
|
|
Ok(bytes) => bytes,
|
|
Err(err) => {
|
|
eprintln!("{}: {}", argv[0], err);
|
|
exit(1);
|
|
},
|
|
};
|
|
|
|
if let Ok(fortune_text) = String::from_utf8(fortune) {
|
|
println!("{}", tell_fortune(fortune_text));
|
|
} else { exit(1) }
|
|
}
|