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