summaryrefslogtreecommitdiff
path: root/src/bin/br/load.rs
diff options
context:
space:
mode:
authorBen Bridle <bridle.benjamin@gmail.com>2025-07-03 15:26:07 +1200
committerBen Bridle <ben@derelict.engineering>2025-07-03 21:24:07 +1200
commit2accc78948fa4a18e37ab0bc405f9b2758acaa3e (patch)
tree2551180ef7fb8f67bfc826de4ad3daf2dd24942e /src/bin/br/load.rs
downloadbedrock-pc-2accc78948fa4a18e37ab0bc405f9b2758acaa3e.zip
Initial commit
Diffstat (limited to 'src/bin/br/load.rs')
-rw-r--r--src/bin/br/load.rs81
1 files changed, 81 insertions, 0 deletions
diff --git a/src/bin/br/load.rs b/src/bin/br/load.rs
new file mode 100644
index 0000000..93a748c
--- /dev/null
+++ b/src/bin/br/load.rs
@@ -0,0 +1,81 @@
+use crate::*;
+
+use std::io::Read;
+use std::path::{Path, PathBuf};
+
+
+pub struct LoadedProgram {
+ pub bytecode: Vec<u8>,
+ pub path: Option<PathBuf>,
+}
+
+/// Load program from path or standard input.
+pub fn load_program(path: Option<&PathBuf>) -> LoadedProgram {
+ if let Some(path) = path {
+ if let Ok(program) = load_program_from_file(path) {
+ let length = program.bytecode.len();
+ info!("Loaded program from {path:?} ({length} bytes)");
+ return program;
+ } else if let Some(program) = load_program_from_env(path) {
+ let length = program.bytecode.len();
+ 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_env(path: &Path) -> Option<LoadedProgram> {
+ // Check that the path is a bare program 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);
+ // Skip relative paths.
+ if !base_path.is_absolute() { continue; }
+ base_path.push(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");
+ if let Ok(program) = load_program_from_file(&base_path) {
+ return Some(program);
+ }
+ }
+ }
+ return None;
+}
+
+/// Attempt to load program from a file path.
+fn load_program_from_file(path: &Path) -> Result<LoadedProgram, 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<LoadedProgram, 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<LoadedProgram, std::io::Error> {
+ let mut bytecode = Vec::<u8>::new();
+ source.take(65536).read_to_end(&mut bytecode)?;
+ return Ok(LoadedProgram { bytecode, path: path.map(|p| p.to_path_buf()) });
+}