From 829dad2c5f8526dfb11f2e4c7e7afd47e46e8998 Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Tue, 3 Jan 2023 12:49:09 -0500 Subject: [PATCH] Added factor applet --- src/cmd/base32/mod.rs | 2 +- src/cmd/factor/mod.rs | 86 ++++++++++++++++++++++++++++++++++++++++++ src/cmd/mod.rs | 2 + src/cmd/shitbox/mod.rs | 4 +- src/lib.rs | 4 +- 5 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 src/cmd/factor/mod.rs diff --git a/src/cmd/base32/mod.rs b/src/cmd/base32/mod.rs index 33605a6..70b8625 100644 --- a/src/cmd/base32/mod.rs +++ b/src/cmd/base32/mod.rs @@ -25,7 +25,7 @@ impl Cmd for Base32 { fn cli(&self) -> clap::Command { Command::new("base32") - .author("The JeanG3nie ") + .author("Nathan Fisher") .about("Base32 encode/decode data and print to standard output") .args([ Arg::new("INPUT") diff --git a/src/cmd/factor/mod.rs b/src/cmd/factor/mod.rs new file mode 100644 index 0000000..8c258af --- /dev/null +++ b/src/cmd/factor/mod.rs @@ -0,0 +1,86 @@ +use clap::{Arg, ArgMatches, Command, value_parser}; +use crate::Cmd; +use std::{error::Error, io::{self, BufRead}}; + +#[derive(Debug)] +pub struct Factor { + name: &'static str, + path: Option, +} + +pub const FACTOR: Factor = Factor { + name: "factor", + path: Some(crate::Path::UsrBin), +}; + +impl Cmd for Factor { + fn name(&self) -> &str { + self.name + } + + fn cli(&self) -> Command { + Command::new("factor") + .about("factor numbers") + .after_help( + "Print the prime factors of each specified integer NUMBER. If none are\n\ + specified on the command line, read them from standard input." + ) + .arg( + Arg::new("number") + .help("the numbers to factor") + .num_args(0..) + .value_parser(value_parser!(u64)) + ) + } + + fn run(&self, matches: Option<&ArgMatches>) -> Result<(), Box> { + if let Some(matches) = matches { + match matches.get_many::("number") { + Some(numbers) => { + numbers.for_each(|n| print_factors(*n)); + }, + None => { + for line in io::stdin().lock().lines() { + for value in line.unwrap().split_whitespace() { + let num: u64 = value.parse()?; + print_factors(num); + } + } + }, + } + } + Ok(()) + } + + fn path(&self) -> Option { + self.path + } +} + +fn is_prime(num: u64) -> bool { + match num { + 0 | 1 => false, + 2 | 3 | 5 | 7 | 11 | 13 => true, + x if x % 2 == 0 => false, + _ => { + let mut x: u64 = 2; + while x < num / 2 { + if num % x == 0 { + return false; + } + x += 1; + } + true + } + } +} + +fn print_factors(num: u64) { + print!("{num}:"); + for n in 2..=num / 2 { + if num % n == 0 && is_prime(n) { + print!(" {n}"); + } + } + println!(); +} diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs index 4d9c130..13e3c9f 100644 --- a/src/cmd/mod.rs +++ b/src/cmd/mod.rs @@ -18,6 +18,7 @@ mod date; mod dd; pub mod dirname; pub mod echo; +pub mod factor; pub mod r#false; mod getty; pub mod head; @@ -41,6 +42,7 @@ pub use { bootstrap::{Bootstrap, BOOTSTRAP}, dirname::{Dirname, DIRNAME}, echo::{Echo, ECHO}, + factor::{Factor, FACTOR}, head::{Head, HEAD}, nologin::{Nologin, NOLOGIN}, r#false::{False, FALSE}, diff --git a/src/cmd/shitbox/mod.rs b/src/cmd/shitbox/mod.rs index ebf689d..2e36137 100644 --- a/src/cmd/shitbox/mod.rs +++ b/src/cmd/shitbox/mod.rs @@ -1,4 +1,4 @@ -use super::{Cmd, BASE_32, BOOTSTRAP, DIRNAME, ECHO, FALSE, HEAD, HOSTNAME, NOLOGIN, SLEEP, TRUE}; +use super::{Cmd, BASE_32, BOOTSTRAP, DIRNAME, ECHO, FACTOR, FALSE, HEAD, HOSTNAME, NOLOGIN, SLEEP, TRUE}; use clap::Command; use std::{ error::Error, @@ -35,6 +35,7 @@ impl Cmd for Shitbox { DIRNAME.cli(), ECHO.cli(), FALSE.cli(), + FACTOR.cli(), HEAD.cli(), NOLOGIN.cli(), HOSTNAME.cli(), @@ -54,6 +55,7 @@ impl Cmd for Shitbox { Some(("bootstrap", matches)) => BOOTSTRAP.run(Some(matches))?, Some(("dirname", matches)) => DIRNAME.run(Some(matches))?, Some(("echo", _matches)) => ECHO.run(None)?, + Some(("factor", matches)) => FACTOR.run(Some(matches))?, Some(("false", _matches)) => FALSE.run(None)?, Some(("head", matches)) => HEAD.run(Some(matches))?, Some(("nologin", _matches)) => NOLOGIN.run(None)?, diff --git a/src/lib.rs b/src/lib.rs index 83920bc..bc43576 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ use std::{env, error::Error, path::PathBuf, string::ToString}; pub mod cmd; use cmd::{ - Cmd, Commands, BASE_32, BOOTSTRAP, DIRNAME, ECHO, FALSE, HEAD, HOSTNAME, NOLOGIN, SHITBOX, SLEEP, TRUE, + Cmd, Commands, BASE_32, BOOTSTRAP, DIRNAME, ECHO, FALSE, FACTOR, HEAD, HOSTNAME, NOLOGIN, SHITBOX, SLEEP, TRUE, }; #[derive(Debug, Clone, Copy)] @@ -39,7 +39,7 @@ pub fn run() -> Result<(), Box> { cmd::COMMANDS .set(Commands { items: vec![ - &BASE_32, &BOOTSTRAP, &DIRNAME, &ECHO, &FALSE, &HEAD, &HOSTNAME, &NOLOGIN, &TRUE, &SLEEP, + &BASE_32, &BOOTSTRAP, &DIRNAME, &ECHO, &FALSE, &FACTOR, &HEAD, &HOSTNAME, &NOLOGIN, &TRUE, &SLEEP, &SHITBOX, ], })