use std::{ env, fs::File, io::{ErrorKind, Read}, process::exit, }; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Default, Debug)] pub enum ScreenType { Terminal, #[default] Window, } pub struct Config { pub rom: Option, pub screen: ScreenType, pub char_rom: Option, } #[derive(Serialize, Deserialize, Debug)] struct ConfigBuilder { rom: Option, char_rom: Option, screen: ScreenType, } impl ConfigBuilder { fn new() -> Self { Self { rom: None, char_rom: None, screen: ScreenType::default(), } } fn build(self) -> Config { let rom = match self.rom { Some(rom) => Some(rom), None => { println!("no rom was provided :("); exit(1); } }; let char_rom = self.char_rom; let screen = self.screen; Config { rom, screen, char_rom, } } } fn help(command: Option) { let executable: String = env::args().next().unwrap(); if let Some(command) = command { match &command as &str { "rom" | "--rom" | "-r" => { println!("{executable} {command} \n\nload a rom/binary from path"); exit(0); } "screen" | "--screen" | "-s" => { println!("{executable} {command} \n\nload a rom/binary from path"); exit(0); } "help" | "--help" | "-h" => { println!("{executable} {command} \n\nshow help info for a given command"); exit(0); } _ => { println!( "{command:?} isn't a valid command!\n\nuse `{executable} help` to see all valid commands", ); exit(1); } } } else { println!("ʕ·ᴥ·ʔ- {executable} is an emulator for george:"); println!("https://git.augustkline.com/august/george\n"); println!("commands:"); println!(" help, -h, --help : print help info for any command"); println!(" rom, -r, --rom : load a rom/binary from path"); println!(" screen, -s, --screen : use the \"terminal\" or \"window\" display type"); println!("\nconfiguration:"); println!(" george-emu searches for a `george.toml` in the current directory.\n in `george.toml` you can specify a path for the character rom using the key `char_rom` and the main rom/binary with the key `rom`"); exit(0); } } pub fn get_input() -> Config { let executable: String = env::args().next().unwrap(); let mut config = ConfigBuilder::new(); let len = env::args().len(); if len == 1 { config = match File::open("./george.toml") { Ok(mut file) => { let mut string = String::new(); file.read_to_string(&mut string).unwrap(); toml::from_str(string.as_str()).unwrap() } Err(_) => { println!("couldn't find a `george.toml` in the current directory!"); println!("\nuse `{executable} --help` to see all config options"); exit(1); } }; return config.build(); } let mut args = env::args().skip(1); while let Some(arg) = args.next() { match &arg[..] { "--help" | "-h" | "help" => help(args.next()), "--rom" | "-r" | "rom" => { if let Some(path) = args.next() { match std::fs::File::open(&path) { Ok(_) => { config.rom = Some(path); } Err(error) => { match error.kind() { ErrorKind::NotFound => { println!("couldn't find the rom at {path:?}"); } ErrorKind::PermissionDenied => { println!( "didn't have sufficient permissions to open the rom at {path:?}" ); } _ => { println!("something went wrong! try again in a moment? really not sure why you're getting this error"); } } exit(1); } }; } else { println!("no rom specified!"); exit(1); } } "--screen" | "-s" | "screen" => { let kind = args.next(); match kind { Some(kind) => match &kind as &str { "terminal" | "Terminal" | "TERMINAL" | "t" | "term" => {} "window" | "Window" | "WINDOW" | "w" | "win" => { config.screen = ScreenType::Window } _ => { println!("{kind:?} isn't a valid screen type!\n\nuse \"{executable} --help screen\" to see all valid screen types"); exit(1); } }, None => { println!("no screen type was provided!\n\nuse \"{executable} --help screen\" to see all valid screen types"); exit(1); } } } _ => { println!("{arg:?} isn't a valid command!\n\nuse \"{executable} help\" to see all valid commands"); exit(1); } } } config.build() }