1use std::collections::{HashMap, HashSet};
5use std::env;
6use std::fs::{File, FileTimes};
7use std::io::Write;
8use std::path::{Path, PathBuf};
9
10use anyhow::Result;
11use clap::crate_version;
12
13use super::display;
14use super::io::{read, read_lib, write_lib, write_obj};
15use super::{Module, LIB};
16
17pub fn info(
19 write: &mut impl Write,
20 lib_or_obj: &Path,
21 code: bool,
22 disassembly: bool,
23) -> Result<()> {
24 let o = read(lib_or_obj)?;
25 let mut options = display::Options::default();
26 if disassembly {
27 options.code_format = display::CodeFormat::Disassembly;
28 } else if code {
29 options.code_format = display::CodeFormat::Hex;
30 }
31 writeln!(write, "{}", display::PsyXDisplayable::wrap(&o, options))?;
32 Ok(())
33}
34
35pub fn split(lib_path: &Path) -> Result<()> {
36 let lib = read_lib(lib_path)?;
37 println!("psyk version {}\n", crate_version!());
38 for module in lib.modules() {
39 let object_filename = format!("{}.OBJ", module.name());
40 let time = module.created_at().expect("created timestamp");
41 let mut file = File::create(&object_filename)?;
42 let times = FileTimes::new().set_accessed(time).set_modified(time);
43 file.set_times(times)?;
44 write_obj(module.object(), &mut file)?;
45
46 println!("Extracted object file {}", object_filename);
47 }
48 Ok(())
49}
50
51pub fn delete(lib_path: &Path, obj_names: Vec<String>) -> Result<()> {
52 let lib = read_lib(lib_path)?;
53
54 let module_names: HashSet<String> = HashSet::from_iter(obj_names);
55
56 let new_modules: Vec<Module> = lib
57 .modules()
58 .iter()
59 .filter(|m| !module_names.contains(&m.name()))
60 .cloned()
61 .collect::<Vec<Module>>();
62 let lib = LIB::new(new_modules);
63
64 let mut file = File::create(lib_path)?;
65 write_lib(&lib, &mut file)
66}
67
68pub fn join(lib_path: &Path, obj_paths: Vec<PathBuf>) -> Result<()> {
69 let modules = obj_paths
70 .iter()
71 .map(|path| Module::new_from_path(path).expect("module"))
72 .collect::<Vec<Module>>();
73
74 let lib = LIB::new(modules);
75
76 let mut file = File::create(lib_path)?;
77 write_lib(&lib, &mut file)
78}
79
80pub fn add(lib_path: &Path, obj_path: &Path) -> Result<()> {
81 let lib = read_lib(lib_path)?;
82
83 let module = Module::new_from_path(obj_path)?;
84 let mut modules: Vec<Module> = lib.modules().clone();
85 modules.push(module);
86
87 let lib = LIB::new(modules);
88
89 let mut file = File::create(lib_path)?;
90 write_lib(&lib, &mut file)
91}
92
93pub fn update(lib_path: &Path, obj_paths: Vec<PathBuf>) -> Result<()> {
94 let lib = read_lib(lib_path)?;
95
96 let mut updated_module_paths: HashMap<String, PathBuf> = HashMap::new();
97 for path in obj_paths {
98 let module_name = String::from(path.file_stem().expect("file").to_string_lossy());
99 updated_module_paths.insert(module_name, path);
100 }
101
102 let new_modules = lib
103 .modules()
104 .iter()
105 .map({
106 |m| {
107 if let Some(module_path) = updated_module_paths.get(&m.name()) {
108 let Ok(new_mod) = Module::new_from_path(module_path) else {
109 eprintln!("could not read: {module_path:?}. Skipping.");
110 return m.clone();
111 };
112 new_mod
113 } else {
114 m.clone()
115 }
116 }
117 })
118 .collect::<Vec<Module>>();
119 let lib = LIB::new(new_modules);
120
121 let mut file = File::create(lib_path)?;
122 write_lib(&lib, &mut file)
123}
124
125fn stem_or_psyk(path: Option<String>) -> String {
126 path.and_then(|path| {
127 Path::new(&path)
128 .file_stem()
129 .and_then(|s| s.to_str())
130 .map(|s| s.to_lowercase())
131 })
132 .unwrap_or_else(|| "psyk".to_string())
133}
134
135pub fn get_binary_name() -> String {
137 stem_or_psyk(env::args().next())
138}
139
140#[cfg(test)]
141mod test {
142 use super::*;
143
144 #[test]
145 fn test_bin_name() {
146 assert_eq!("psyk", stem_or_psyk(None));
147 assert_eq!("foo", stem_or_psyk(Some("/bin/foo".into())));
148 }
149}