mindustry logic execution, map- and schematic- parsing and rendering
Move executable parts into a submodule
| -rw-r--r-- | src/exe/args.rs (renamed from src/args.rs) | 0 | ||||
| -rw-r--r-- | src/exe/mod.rs | 14 | ||||
| -rw-r--r-- | src/exe/print.rs | 210 | ||||
| -rw-r--r-- | src/main.rs | 219 |
4 files changed, 226 insertions, 217 deletions
diff --git a/src/args.rs b/src/exe/args.rs index 9ea30aa..9ea30aa 100644 --- a/src/args.rs +++ b/src/exe/args.rs diff --git a/src/exe/mod.rs b/src/exe/mod.rs new file mode 100644 index 0000000..53e74dc --- /dev/null +++ b/src/exe/mod.rs @@ -0,0 +1,14 @@ +use std::env::Args; + +pub mod args; +pub mod print; + +pub fn main(mut args: Args) +{ + match args.next() + { + None => panic!("not enough arguments"), + Some(s) if s == "print" => print::main(args), + Some(s) => panic!("unknown argument {s}"), + } +} diff --git a/src/exe/print.rs b/src/exe/print.rs new file mode 100644 index 0000000..7cb3479 --- /dev/null +++ b/src/exe/print.rs @@ -0,0 +1,210 @@ +use std::borrow::Cow; +use std::env::Args; +use std::io::{self, Write}; +use std::fs; + +use crate::block::build_registry; +use crate::data::{DataRead, Serializer}; +use crate::data::schematic::{Schematic, SchematicSerializer}; +use crate::exe::args::{self, ArgCount, ArgOption, OptionError, OptionHandler}; + +pub fn main(mut args: Args) +{ + let mut handler = OptionHandler::new(); + let opt_file = handler.add(ArgOption::new(Some('f'), Some(Cow::Borrowed("file")), ArgCount::Required(usize::MAX))).unwrap(); + let opt_interact = handler.add(ArgOption::new(Some('i'), Some(Cow::Borrowed("interactive")), ArgCount::Forbidden)).unwrap(); + match args::parse(&mut args, &mut handler) + { + Err(args::Error::Handler{pos, val: OptionError::NoSuchShort(short)}) => + { + println!("Invalid argument \"-{short}\" (at #{})).", pos + 1); + return; + }, + Err(args::Error::Handler{pos, val: OptionError::NoSuchLong(long)}) => + { + println!("Invalid argument \"--{long}\" (at #{})).", pos + 1); + return; + }, + Err(args::Error::Handler{pos, val: OptionError::ValueForbidden(opt)}) => + { + match (opt.get_short(), opt.get_long()) + { + (None, None) => unreachable!("unnamed ArgOption (at #{}))", pos + 1), + (None, Some(long)) => println!("Illegal valued argument \"--{long}\" (at #{})).", pos + 1), + (Some(short), None) => println!("Illegal valued argument \"-{short}\" (at #{})).", pos + 1), + (Some(short), Some(long)) => println!("Illegal valued argument \"--{long}\" (\"-{short}\", at #{})).", pos + 1), + } + return; + }, + Err(args::Error::Handler{pos, val: OptionError::ValueRequired(opt)}) => + { + match (opt.get_short(), opt.get_long()) + { + (None, None) => unreachable!("unnamed ArgOption (at #{}))", pos + 1), + (None, Some(long)) => println!("Missing value to argument \"--{long}\" (at #{})).", pos + 1), + (Some(short), None) => println!("Missing value to argument \"-{short}\" (at #{})).", pos + 1), + (Some(short), Some(long)) => println!("Missing value to argument \"--{long}\" (\"-{short}\", at #{})).", pos + 1), + } + return; + }, + Err(args::Error::Handler{pos, val: OptionError::TooMany(opt)}) => + { + let max = opt.get_count().get_max_count().unwrap(); + match (opt.get_short(), opt.get_long()) + { + (None, None) => unreachable!("unnamed ArgOption (at #{}))", pos + 1), + (None, Some(long)) => println!("Duplicate argument \"--{long}\" (more than {max} at #{})).", pos + 1), + (Some(short), None) => println!("Duplicate argument \"-{short}\" (more than {max} at #{})).", pos + 1), + (Some(short), Some(long)) => println!("Duplicate argument \"--{long}\" (\"-{short}\", more than {max} at #{})).", pos + 1), + } + return; + }, + Err(args::Error::EmptyName{pos}) => + { + println!("Invalid empty argument (at #{}).", pos + 1); + return; + }, + _ => (), + } + + let reg = build_registry(); + let mut ss = SchematicSerializer(®); + let mut first = true; + let mut need_space = false; + // process the files if any + let file = match handler.get_value(opt_file).get_values() + { + None => false, + Some(paths) => + { + for path in paths + { + match fs::read(path) + { + Ok(data) => + { + match ss.deserialize(&mut DataRead::new(&data)) + { + Ok(s) => + { + if !first || need_space {println!();} + first = false; + need_space = true; + println!("Schematic: @{path}"); + print_schematic(&s); + }, + // continue processing files, literals & maybe interactive mode + Err(e) => + { + if need_space {println!();} + first = false; + need_space = false; + println!("Could not read schematic: {e:?}"); + }, + } + }, + // continue processing files, literals & maybe interactive mode + Err(e) => + { + if need_space {println!();} + first = false; + need_space = false; + println!("Could not read file {path:?}: {e}"); + }, + } + } + true + }, + }; + // process schematics from command line + for curr in handler.get_literals() + { + match ss.deserialize_base64(curr) + { + Ok(s) => + { + if !first || need_space {println!();} + first = false; + need_space = true; + println!("Schematic: {curr}"); + print_schematic(&s); + }, + // continue processing literals & maybe interactive mode + Err(e) => + { + if need_space {println!();} + first = false; + need_space = false; + println!("Could not read schematic: {e:?}"); + }, + } + } + // if --interactive or no schematics: continue parsing from console + if handler.get_value(opt_interact).is_present() || (!file && handler.get_literals().is_empty()) + { + if need_space {println!();} + need_space = false; + println!("Entering interactive mode, paste schematic to print details."); + let mut buff = String::new(); + let stdin = io::stdin(); + loop + { + buff.clear(); + if need_space {println!();} + need_space = false; + print!("> "); + if let Err(e) = io::stdout().flush() + { + // what the print & println macros would do + panic!("failed printing to stdout: {e}"); + } + match stdin.read_line(&mut buff) + { + Ok(..) => + { + let data = buff.trim(); + if data.is_empty() {break;} + match ss.deserialize_base64(data) + { + Ok(s) => + { + println!(); + need_space = true; + print_schematic(&s) + }, + // continue interactive mode, typos are especially likely here + Err(e) => + { + if need_space {println!();} + need_space = false; + println!("Could not read schematic: {e:?}") + }, + } + }, + Err(e) => + { + if need_space {println!();} + println!("Failed to read next line: {e}"); + break; + }, + } + } + } +} + +fn print_schematic(s: &Schematic) +{ + if let Some(name) = s.get_tags().get("name") + { + if !name.is_empty() {println!("Name: {name}");} + } + if let Some(desc) = s.get_tags().get("description") + { + if !desc.is_empty() {println!("Desc: {desc}");} + } + if let Some(labels) = s.get_tags().get("labels") + { + if !labels.is_empty() && labels != "[]" {println!("Tags: {:?}", labels);} + } + println!("\n{s}"); +} diff --git a/src/main.rs b/src/main.rs index 7f82218..b987cf4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,227 +1,12 @@ -use std::borrow::Cow; -use std::env::Args; -use std::io::{self, Write}; -use std::fs; - -use crate::args::{ArgCount, ArgOption, OptionError, OptionHandler}; -use crate::data::{DataRead, Serializer}; -use crate::data::schematic::{Schematic, SchematicSerializer}; - pub mod access; -pub mod args; pub mod block; pub mod data; +pub mod exe; pub mod logic; fn main() { let mut args = std::env::args(); args.next().unwrap(); // path to executable - match args.next() - { - None => panic!("not enough arguments"), - Some(s) if s == "print" => main_print(args), - Some(s) => panic!("unknown argument {s}"), - } -} - -fn main_print(mut args: Args) -{ - let mut handler = OptionHandler::new(); - let opt_file = handler.add(ArgOption::new(Some('f'), Some(Cow::Borrowed("file")), ArgCount::Required(usize::MAX))).unwrap(); - let opt_interact = handler.add(ArgOption::new(Some('i'), Some(Cow::Borrowed("interactive")), ArgCount::Forbidden)).unwrap(); - match args::parse(&mut args, &mut handler) - { - Err(args::Error::Handler{pos, val: OptionError::NoSuchShort(short)}) => - { - println!("Invalid argument \"-{short}\" (at #{})).", pos + 1); - return; - }, - Err(args::Error::Handler{pos, val: OptionError::NoSuchLong(long)}) => - { - println!("Invalid argument \"--{long}\" (at #{})).", pos + 1); - return; - }, - Err(args::Error::Handler{pos, val: OptionError::ValueForbidden(opt)}) => - { - match (opt.get_short(), opt.get_long()) - { - (None, None) => unreachable!("unnamed ArgOption (at #{}))", pos + 1), - (None, Some(long)) => println!("Illegal valued argument \"--{long}\" (at #{})).", pos + 1), - (Some(short), None) => println!("Illegal valued argument \"-{short}\" (at #{})).", pos + 1), - (Some(short), Some(long)) => println!("Illegal valued argument \"--{long}\" (\"-{short}\", at #{})).", pos + 1), - } - return; - }, - Err(args::Error::Handler{pos, val: OptionError::ValueRequired(opt)}) => - { - match (opt.get_short(), opt.get_long()) - { - (None, None) => unreachable!("unnamed ArgOption (at #{}))", pos + 1), - (None, Some(long)) => println!("Missing value to argument \"--{long}\" (at #{})).", pos + 1), - (Some(short), None) => println!("Missing value to argument \"-{short}\" (at #{})).", pos + 1), - (Some(short), Some(long)) => println!("Missing value to argument \"--{long}\" (\"-{short}\", at #{})).", pos + 1), - } - return; - }, - Err(args::Error::Handler{pos, val: OptionError::TooMany(opt)}) => - { - let max = opt.get_count().get_max_count().unwrap(); - match (opt.get_short(), opt.get_long()) - { - (None, None) => unreachable!("unnamed ArgOption (at #{}))", pos + 1), - (None, Some(long)) => println!("Duplicate argument \"--{long}\" (more than {max} at #{})).", pos + 1), - (Some(short), None) => println!("Duplicate argument \"-{short}\" (more than {max} at #{})).", pos + 1), - (Some(short), Some(long)) => println!("Duplicate argument \"--{long}\" (\"-{short}\", more than {max} at #{})).", pos + 1), - } - return; - }, - Err(args::Error::EmptyName{pos}) => - { - println!("Invalid empty argument (at #{}).", pos + 1); - return; - }, - _ => (), - } - - let reg = block::build_registry(); - let mut ss = SchematicSerializer(®); - let mut first = true; - let mut need_space = false; - // process the files if any - let file = match handler.get_value(opt_file).get_values() - { - None => false, - Some(paths) => - { - for path in paths - { - match fs::read(path) - { - Ok(data) => - { - match ss.deserialize(&mut DataRead::new(&data)) - { - Ok(s) => - { - if !first || need_space {println!();} - first = false; - need_space = true; - println!("Schematic: @{path}"); - print_schematic(&s); - }, - // continue processing files, literals & maybe interactive mode - Err(e) => - { - if need_space {println!();} - first = false; - need_space = false; - println!("Could not read schematic: {e:?}"); - }, - } - }, - // continue processing files, literals & maybe interactive mode - Err(e) => - { - if need_space {println!();} - first = false; - need_space = false; - println!("Could not read file {path:?}: {e}"); - }, - } - } - true - }, - }; - // process schematics from command line - for curr in handler.get_literals() - { - match ss.deserialize_base64(curr) - { - Ok(s) => - { - if !first || need_space {println!();} - first = false; - need_space = true; - println!("Schematic: {curr}"); - print_schematic(&s); - }, - // continue processing literals & maybe interactive mode - Err(e) => - { - if need_space {println!();} - first = false; - need_space = false; - println!("Could not read schematic: {e:?}"); - }, - } - } - // if --interactive or no schematics: continue parsing from console - if handler.get_value(opt_interact).is_present() || (!file && handler.get_literals().is_empty()) - { - if need_space {println!();} - need_space = false; - println!("Entering interactive mode, paste schematic to print details."); - let mut buff = String::new(); - let stdin = io::stdin(); - loop - { - buff.clear(); - if need_space {println!();} - need_space = false; - print!("> "); - if let Err(e) = io::stdout().flush() - { - // what the print & println macros would do - panic!("failed printing to stdout: {e}"); - } - match stdin.read_line(&mut buff) - { - Ok(..) => - { - let data = buff.trim(); - if data.is_empty() {break;} - match ss.deserialize_base64(data) - { - Ok(s) => - { - println!(); - need_space = true; - print_schematic(&s) - }, - // continue interactive mode, typos are especially likely here - Err(e) => - { - if need_space {println!();} - need_space = false; - println!("Could not read schematic: {e:?}") - }, - } - }, - Err(e) => - { - if need_space {println!();} - println!("Failed to read next line: {e}"); - break; - }, - } - } - } -} - -fn print_schematic(s: &Schematic) -{ - if let Some(name) = s.get_tags().get("name") - { - if !name.is_empty() {println!("Name: {name}");} - } - if let Some(desc) = s.get_tags().get("description") - { - if !desc.is_empty() {println!("Desc: {desc}");} - } - if let Some(labels) = s.get_tags().get("labels") - { - if !labels.is_empty() && labels != "[]" {println!("Tags: {:?}", labels);} - } - println!("\n{s}"); + exe::main(args); } |