ableos_userland/libraries/clparse/src/lib.rs
2022-12-03 12:15:03 -06:00

211 lines
5.7 KiB
Rust

//! # clparse
//! simple command line parser for ableOS
#![no_std]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
use hashbrown;
use hashbrown::HashMap;
use alloc::string::String;
pub use toml;
pub type Argmap = HashMap<String, String>;
#[derive(Debug, Clone)]
pub struct Arguments {
pub arguments: Argmap,
}
impl Arguments {
// TODO: Maybe check if a key is truthy, like if it's value equals "true", "1", "on", etc.
// NOTE: The above is out of scope for this pr but will be considered -able
pub fn parse(command: String) -> Result<Arguments, CLparseErrors> {
// TODO: Parse one implicit arg.
// NOTE: The above is out of scope for this pr but will be considered -able
let mut cmd = Arguments {
arguments: HashMap::new(),
};
if !command.is_empty() {
let command_split = command.split(" ");
for kv_pair in command_split {
if kv_pair.contains("=") {
// println!("{kv_pair}");
let mut kv_split = kv_pair.split("=");
let key = kv_split.next().unwrap().to_string();
// println!("{key}");
let value = kv_split.next().unwrap().to_string();
// println!("{value}");
cmd.arguments.insert(key, value);
} else {
return Err(CLparseErrors::MissingEquals);
}
}
}
Ok(cmd)
}
pub fn parse_from_string<S: Into<String>>(
string: S,
) -> Result<(Value, Arguments), CLparseErrors> {
let config: toml::Value = Value::String("".to_string());
let args = Arguments::parse(string.into())?;
return Ok((config, args));
}
#[cfg(feature = "std")]
pub fn parse_from_args() -> Result<(Value, Arguments), CLparseErrors> {
use std::{
collections::{BTreeMap, HashMap},
env,
fs::File,
io::{Read, Write},
println,
};
use alloc::format;
let args = env::args();
let mut args_str = String::new();
let dir = env::current_dir().unwrap();
let mut config: toml::Value = Value::String("".to_string());
match env::current_exe() {
Ok(bin) => {
if let Some(exe_name) = bin.as_path().file_name() {
let exe_name = exe_name.to_str().unwrap();
// println!("{exe_name}");
let path = format!(
"/home/{}/configs/{}/config.toml",
env::var("USER").unwrap(),
exe_name
);
let path = std::path::Path::new(&path);
if path.exists() {
let display = path.display();
let mut file = match File::open(&path) {
Err(why) => panic!("couldn't open {}: {}", display, why),
Ok(file) => file,
};
let mut s = String::new();
match file.read_to_string(&mut s) {
Err(why) => panic!("couldn't read {}: {}", display, why),
Ok(_) => {
// print!("{} contains:\n{}", display, s)
}
}
config = toml::from_str(&s).unwrap();
} else {
let mut file = File::create(path);
println!("Make a file in your home dir called \"configs\"");
file.unwrap().write_all(b"Hello, world!").unwrap();
}
}
}
Err(_) => todo!(),
}
for (count, arg) in args.enumerate() {
if count == 0 || count == 1 {
// Ignore stdio + program name on unix
} else {
args_str.push_str(&arg);
args_str.push(' ');
}
}
// needed to remove the very last ` ` which is unneeded
args_str.pop();
// println!("{args_str}");
let ret = Arguments::parse(args_str)?;
return Ok((config, ret));
}
pub fn is_truthy(&self, key: &str) -> bool {
match self.arguments.get(key) {
Some(val) => {
let val = val.to_lowercase();
if val == "true" || val == "1" || val == "on" || val == "t" {
return true;
}
false
}
None => false,
}
}
}
#[derive(Debug)]
pub enum CLparseErrors {
MalformendArgument,
MissingEquals,
}
impl Display for CLparseErrors {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self)?;
Ok(())
}
}
use core::fmt::Display;
use crate::alloc::string::ToString;
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(feature = "std")]
fn test_arg_parse() {
use std::println;
let argline = "abc=xyz".to_string();
match Arguments::parse(argline) {
Ok(ok) => {
println!("{ok:?}")
}
Err(err) => panic!("{err:?}"),
}
}
#[test]
fn fail_test_arg_parse() {
let argline = "abcxyz".to_string();
match Arguments::parse(argline) {
Ok(ok) => panic!("{ok:?}"),
Err(_) => {}
}
}
}
use toml::Value;
#[test]
#[cfg(feature = "std")]
pub fn load_config() {
use std::println;
let toml_str = include_str!("../assets/example.toml");
let decoded: Value = toml::from_str(toml_str).unwrap();
println!("{}", decoded);
}