summaryrefslogtreecommitdiff
path: root/src/load_program.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/load_program.rs')
-rw-r--r--src/load_program.rs93
1 files changed, 93 insertions, 0 deletions
diff --git a/src/load_program.rs b/src/load_program.rs
new file mode 100644
index 0000000..0473207
--- /dev/null
+++ b/src/load_program.rs
@@ -0,0 +1,93 @@
+use crate::*;
+
+use std::io::Read;
+
+
+pub struct Program {
+ pub bytecode: Vec<u8>,
+ pub path: Option<PathBuf>,
+}
+
+impl Program {
+ fn path(&self) -> String {
+ match &self.path {
+ Some(path) => path.as_os_str().to_string_lossy().to_string(),
+ None => String::from("<unknown>"),
+ }
+ }
+}
+
+
+/// Load program from path or standard input.
+pub fn load_program(path: Option<&PathBuf>) -> Program {
+ if let Some(path) = path {
+ if let Ok(program) = load_program_from_file(path) {
+ let length = program.bytecode.len();
+ let path = program.path();
+ info!("Loaded program from {path:?} ({length} bytes)");
+ return program;
+ } else if let Some(program) = load_program_from_bedrock_path(path) {
+ let length = program.bytecode.len();
+ let path = program.path();
+ info!("Loaded program from {path:?} ({length} bytes)");
+ return program;
+ } else {
+ fatal!("Could not read program from {path:?}");
+ }
+ } else {
+ info!("Reading program from standard input...");
+ if let Ok(program) = load_program_from_stdin() {
+ let length = program.bytecode.len();
+ info!("Loaded program from standard input ({length} bytes)");
+ return program;
+ } else {
+ fatal!("Could not read program from standard input");
+ }
+ }
+}
+
+/// Attempt to load program from a directory in the BEDROCK_PATH environment variable.
+fn load_program_from_bedrock_path(path: &Path) -> Option<Program> {
+ // Only if the path can be treated as a file name.
+ if path.is_relative() && path.components().count() == 1 {
+ for base_path in std::env::var("BEDROCK_PATH").ok()?.split(':') {
+ let mut base_path = PathBuf::from(base_path);
+ if !base_path.is_absolute() { continue; }
+ base_path.push(path);
+ info!("Attempting to load program from {base_path:?}");
+ if let Ok(program) = load_program_from_file(&base_path) {
+ return Some(program);
+ }
+ if path.extension().is_some() { continue; }
+ base_path.set_extension("br");
+ info!("Attempting to load program from {base_path:?}");
+ if let Ok(program) = load_program_from_file(&base_path) {
+ return Some(program);
+ }
+ }
+ }
+ return None;
+}
+
+/// Attempt to load program from a specific file path.
+fn load_program_from_file(path: &Path) -> Result<Program, std::io::Error> {
+ // Canonicalize paths so that symbolic links to program files resolve to
+ // the real program directory, which could contain a symbols file.
+ let path = match path.canonicalize() {
+ Ok(canonical) => canonical,
+ Err(_) => path.to_path_buf(),
+ };
+ load_program_from_readable_source(std::fs::File::open(&path)?, Some(&path))
+}
+
+/// Attempt to load program from standard input.
+fn load_program_from_stdin() -> Result<Program, std::io::Error> {
+ load_program_from_readable_source(std::io::stdin(), None)
+}
+
+/// Attempt to load program from a source that implements std::io::Read.
+fn load_program_from_readable_source(source: impl Read, path: Option<&Path>) -> Result<Program, std::io::Error> {
+ let mut bytecode = Vec::<u8>::new();
+ source.take(65536).read_to_end(&mut bytecode)?;
+ return Ok(Program { bytecode, path: path.map(|p| p.to_path_buf()) });
+}