use crate::*; use std::io::Read; use std::path::{Path, PathBuf}; pub struct LoadedProgram { pub bytecode: Vec, pub path: Option, } /// 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 { // 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 { // 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 { 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 { let mut bytecode = Vec::::new(); source.take(65536).read_to_end(&mut bytecode)?; return Ok(LoadedProgram { bytecode, path: path.map(|p| p.to_path_buf()) }); }