diff options
author | Ben Bridle <bridle.benjamin@gmail.com> | 2025-07-03 15:26:07 +1200 |
---|---|---|
committer | Ben Bridle <ben@derelict.engineering> | 2025-07-03 21:24:07 +1200 |
commit | 2accc78948fa4a18e37ab0bc405f9b2758acaa3e (patch) | |
tree | 2551180ef7fb8f67bfc826de4ad3daf2dd24942e /src/bin/br/load.rs | |
download | bedrock-pc-2accc78948fa4a18e37ab0bc405f9b2758acaa3e.zip |
Initial commit
Diffstat (limited to 'src/bin/br/load.rs')
-rw-r--r-- | src/bin/br/load.rs | 81 |
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()) }); +} |