use std::collections::HashMap;
use std::sync::Mutex;
use once_cell::sync::Lazy;
use crate::ported::utils::zwarnnam;
use crate::ported::zsh_h::mathfunc;
use crate::zsh_h::module;
use crate::ported::zsh_h::OPT_ISSET;
pub static MATHFUNCS: Lazy<Mutex<Vec<mathfunc>>> = Lazy::new(|| Mutex::new(Vec::new()));
pub static HOOKTAB: Lazy<Mutex<HashMap<String, Vec<String>>>> = Lazy::new(|| Mutex::new(HashMap::new()));
pub static MODULESTAB: Lazy<Mutex<modulestab>> = Lazy::new(|| Mutex::new(modulestab::new()));
pub fn addhookfunc(hook: &str, func: &str) { if let Ok(mut tab) = HOOKTAB.lock() {
tab.entry(hook.to_string())
.or_default()
.push(func.to_string());
}
}
pub fn deletehookfunc(hook: &str, func: &str) { if let Ok(mut tab) = HOOKTAB.lock() {
if let Some(v) = tab.get_mut(hook) {
v.retain(|f| f != func);
}
}
}
pub const FEATURE_TYPE_BUILTIN: i32 = 0;
pub const FEATURE_TYPE_CONDITION: i32 = 1;
pub const FEATURE_TYPE_PARAMETER: i32 = 2;
pub const FEATURE_TYPE_MATHFUNC: i32 = 3;
pub const FEATURE_TYPE_HOOK: i32 = 4;
#[derive(Debug, Default)]
pub struct modulestab {
modules: HashMap<String, module>,
autoload_builtins: HashMap<String, String>,
autoload_conditions: HashMap<String, String>,
autoload_params: HashMap<String, String>,
autoload_mathfuncs: HashMap<String, String>,
hooks: HashMap<String, Vec<String>>,
}
pub const BINF_ADDED: u32 = 1 << 3;
pub const CONDF_INFIX: u32 = 1;
pub const CONDF_ADDED: u32 = 1 << 1;
pub const MFF_ADDED: u32 = 1 << 1;
impl modulestab {
pub fn new() -> Self {
let mut table = Self::default();
table.register_builtin_modules();
table
}
fn register_builtin_modules(&mut self) {
let builtin_modules = [
(
"zsh/complete",
&[
"compctl",
"compcall",
"comparguments",
"compdescribe",
"compfiles",
"compgroups",
"compquote",
"comptags",
"comptry",
"compvalues",
][..],
),
("zsh/complist", &["complist"][..]),
("zsh/computil", &["compadd", "compset"][..]),
("zsh/datetime", &["output_strftime"][..]),
(
"zsh/files",
&[
"mkdir", "rmdir", "ln", "mv", "cp", "rm", "chmod", "chown", "sync",
][..],
),
("zsh/langinfo", &[][..]),
("zsh/mapfile", &[][..]),
("zsh/mathfunc", &[][..]),
("zsh/nearcolor", &[][..]),
("zsh/net/socket", &["zsocket"][..]),
("zsh/net/tcp", &["ztcp"][..]),
("zsh/parameter", &[][..]),
(
"zsh/pcre",
&["pcre_compile", "pcre_match", "pcre_study"][..],
),
("zsh/regex", &[][..]),
("zsh/sched", &["sched"][..]),
("zsh/stat", &["zstat"][..]),
(
"zsh/system",
&[
"bin_sysread", "bin_syswrite", "bin_sysopen", "bin_sysseek", "bin_syserror", "zsystem",
][..],
),
("zsh/termcap", &["echotc"][..]),
("zsh/terminfo", &["echoti"][..]),
("zsh/watch", &["log"][..]),
("zsh/zftp", &["zftp"][..]),
("zsh/zleparameter", &[][..]),
("zsh/zprof", &["zprof"][..]),
("zsh/zpty", &["zpty"][..]),
("zsh/zselect", &["zselect"][..]),
(
"zsh/zutil",
&["zstyle", "zformat", "zparseopts", "zregexparse"][..],
),
(
"zsh/attr",
&["zgetattr", "zsetattr", "zdelattr", "zlistattr"][..],
),
("zsh/cap", &["cap", "getcap", "setcap"][..]),
("zsh/clone", &["clone"][..]),
("zsh/curses", &["zcurses"][..]),
("zsh/db/gdbm", &["ztie", "zuntie", "zgdbmpath"][..]),
("zsh/param/private", &["private"][..]),
];
for (name, _builtins) in &builtin_modules {
let module = module::new(name);
self.modules.insert(name.to_string(), module);
}
}
pub fn load_module(&mut self, name: &str) -> bool { if self.modules.contains_key(name) {
if let Some(m) = self.modules.get_mut(name) {
m.node.flags = (m.node.flags | crate::ported::zsh_h::MOD_LINKED)
& !crate::ported::zsh_h::MOD_UNLOAD;
}
return true;
}
false
}
pub fn unload_module(&mut self, name: &str) -> bool { if let Some(module) = self.modules.get_mut(name) {
module.node.flags |= crate::ported::zsh_h::MOD_UNLOAD;
return true;
}
false
}
pub fn is_loaded(&self, name: &str) -> bool {
self.modules
.get(name)
.map(|m| m.is_loaded())
.unwrap_or(false)
}
pub fn list_loaded(&self) -> Vec<&str> {
self.modules
.iter()
.filter(|(_, m)| m.is_loaded())
.map(|(name, _)| name.as_str())
.collect()
}
pub fn list_all(&self) -> Vec<(&str, i32)> {
self.modules
.iter()
.map(|(name, m)| (name.as_str(), m.node.flags))
.collect()
}
pub fn addbuiltin(&mut self, _name: &str, _module: &str) { }
pub fn deletebuiltin(&mut self, _name: &str, _module: &str) { }
pub fn add_autobin(&mut self, name: &str, module: &str) { self.autoload_builtins
.insert(name.to_string(), module.to_string());
}
pub fn del_autobin(&mut self, name: &str) { self.autoload_builtins.remove(name);
}
pub fn setbuiltins(&mut self, module: &str, names: &[&str]) {
for name in names {
self.addbuiltin(name, module);
}
}
pub fn addconddef(&mut self, _name: &str, _module: &str) { }
pub fn deleteconddef(&mut self, _name: &str, _module: &str) {
}
pub fn getconddef(&self, name: &str) -> Option<&str> {
self.autoload_conditions.get(name).map(|s| s.as_str())
}
pub fn add_autocond(&mut self, name: &str, module: &str) {
self.autoload_conditions
.insert(name.to_string(), module.to_string());
}
pub fn del_autocond(&mut self, name: &str) {
self.autoload_conditions.remove(name);
}
pub fn addhookdef(&mut self, h: &str) { self.hooks.entry(h.to_string()).or_default();
}
pub fn addhookdefs(&mut self, names: &[&str]) {
for name in names {
self.addhookdef(name);
}
}
pub fn deletehookdef(&mut self, name: &str) { self.hooks.remove(name);
}
pub fn deletehookdefs(&mut self, names: &[&str]) {
for name in names {
self.deletehookdef(name);
}
}
pub fn addhookfunc(&mut self, n: &str, f: &str) {
self.hooks
.entry(n.to_string())
.or_default()
.push(f.to_string());
}
pub fn deletehookfunc(&mut self, n: &str, f: &str) {
if let Some(funcs) = self.hooks.get_mut(n) {
funcs.retain(|f| f != f);
}
}
pub fn gethookdef(&self, n: &str) -> Option<&Vec<String>> {
self.hooks.get(n)
}
pub fn runhookdef(&self, name: &str) -> Vec<String> { self.hooks.get(name).cloned().unwrap_or_default()
}
pub fn addparamdef(&mut self, _name: &str, _module: &str) {
}
pub fn deleteparamdef(&mut self, _name: &str, _module: &str) {
}
pub fn setparamdefs(&mut self, module: &str, names: &[&str]) {
for name in names {
self.addparamdef(name, module);
}
}
pub fn add_autoparam(&mut self, name: &str, module: &str) {
self.autoload_params
.insert(name.to_string(), module.to_string());
}
pub fn del_autoparam(&mut self, name: &str) {
self.autoload_params.remove(name);
}
pub fn enable_feature(&mut self, module: &str, _name: &str) -> bool {
self.modules.contains_key(module)
}
pub fn disable_feature(&mut self, module: &str, _name: &str) -> bool {
self.modules.contains_key(module)
}
pub fn list_features(&self, _module: &str) -> Vec<String> {
Vec::new()
}
pub fn module_linked(&self, name: &str) -> bool {
self.modules.contains_key(name)
}
pub fn resolve_autoload_builtin(&self, name: &str) -> Option<&str> {
self.autoload_builtins.get(name).map(|s| s.as_str())
}
pub fn resolve_autoload_param(&self, name: &str) -> Option<&str> {
self.autoload_params.get(name).map(|s| s.as_str())
}
pub fn ensurefeature(&mut self, module: &str, feature: &str) -> bool {
if !self.is_loaded(module) {
self.load_module(module);
}
self.is_loaded(module)
}
}
pub trait ModuleLifecycle {
fn setup(&mut self) -> i32 {
0
}
fn boot(&mut self) -> i32 {
0
}
fn cleanup(&mut self) -> i32 {
0
}
fn finish(&mut self) -> i32 {
0
}
}
pub fn freemodulenode(hn: module) {
}
pub fn printmodulenode(hn: &str, m: &module) -> String {
let state = if (m.node.flags & crate::ported::zsh_h::MOD_ALIAS) != 0 {
"alias"
} else if (m.node.flags & crate::ported::zsh_h::MOD_UNLOAD) != 0 {
"unloaded"
} else if (m.node.flags & crate::ported::zsh_h::MOD_LINKED) != 0 {
"loaded"
} else {
"autoloaded"
};
format!("{} ({})", hn, state)
}
pub fn newmoduletable() -> modulestab {
modulestab::new()
}
pub fn register_module(table: &mut modulestab, name: &str) -> bool { if table.modules.contains_key(name) {
return false;
}
table.modules.insert(name.to_string(), module::new(name));
true
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_module_table_new() {
let table = modulestab::new();
assert!(table.is_loaded("zsh/complete"));
assert!(table.is_loaded("zsh/datetime"));
assert!(table.is_loaded("zsh/system"));
assert!(!table.is_loaded("nonexistent"));
}
#[test]
fn test_load_unload() {
let mut table = modulestab::new();
assert!(table.is_loaded("zsh/complete"));
table.unload_module("zsh/complete");
assert!(!table.is_loaded("zsh/complete"));
table.load_module("zsh/complete");
assert!(table.is_loaded("zsh/complete"));
}
#[test]
fn test_list_loaded() {
let table = modulestab::new();
let loaded = table.list_loaded();
assert!(loaded.len() > 20);
assert!(loaded.contains(&"zsh/complete"));
}
#[test]
fn test_hooks() {
let mut table = modulestab::new();
table.addhookdef("chpwd");
table.addhookfunc("chpwd", "my_chpwd_handler");
let funcs = table.runhookdef("chpwd");
assert_eq!(funcs, vec!["my_chpwd_handler"]);
table.deletehookfunc("chpwd", "my_chpwd_handler");
let funcs = table.runhookdef("chpwd");
assert!(funcs.is_empty());
}
#[test]
fn test_autoload() {
let mut table = modulestab::new();
table.add_autobin("my_cmd", "zsh/mymodule");
assert_eq!(
table.resolve_autoload_builtin("my_cmd"),
Some("zsh/mymodule")
);
assert_eq!(table.resolve_autoload_builtin("nonexistent"), None);
}
#[test]
fn test_features() {
let table = modulestab::new();
let features = table.list_features("zsh/complete");
assert!(features.is_empty());
assert!(table.module_linked("zsh/complete"));
}
#[test]
fn test_module_linked() {
let table = modulestab::new();
assert!(table.module_linked("zsh/complete"));
assert!(table.module_linked("zsh/stat"));
assert!(!table.module_linked("zsh/nonexistent"));
}
#[test]
fn test_printmodulenode() {
let module = module::new("zsh/test");
let output = printmodulenode("zsh/test", &module);
assert!(output.contains("zsh/test"));
assert!(output.contains("loaded"));
}
}
pub const FEAT_IGNORE: i32 = 0x0001;
pub const FEAT_INFIX: i32 = 0x0002;
pub const FEAT_AUTOALL: i32 = 0x0004;
pub const FEAT_REMOVE: i32 = 0x0008;
pub const FEAT_CHECKAUTO: i32 = 0x0010;
pub fn add_automathfunc(table: &mut modulestab, module: &str, fnam: &str, flags: i32) -> i32 { if table.autoload_mathfuncs.contains_key(fnam) { if (flags & FEAT_IGNORE) == 0 { return 1; }
} else {
table.autoload_mathfuncs.insert(fnam.to_string(), module.to_string());
}
0 }
pub fn add_dep(table: &mut modulestab, name: &str, from: &str) -> i32 { let canon = match find_module(table, name, FINDMOD_ALIASP | FINDMOD_CREATE) {
Some(n) => n,
None => return 0,
};
if let Some(m) = table.modules.get_mut(&canon) {
let deps = m.deps.get_or_insert_with(crate::ported::linklist::LinkList::new);
if !deps.iter().any(|d| d == from) { deps.push_back(from.to_string()); }
}
0
}
pub fn addhookdeffunc(table: &mut modulestab, h: &mut crate::ported::zsh_h::hookdef, fn_name: &str) -> i32 { table.hooks.entry(h.name.clone()).or_default().push(fn_name.to_string());
let _ = h.funcs; 0 }
pub fn autofeatures(table: &mut modulestab, _cmdnam: &str, module: Option<&str>,
features: &[String], prefchar: u8, defflags: i32) -> i32 { let mut ret: i32 = 0;
let _ = defflags;
for feature in features {
let mut s = feature.as_str();
let mut add: bool = true; if let Some(rest) = s.strip_prefix('-') {
add = false;
s = rest;
} else if let Some(rest) = s.strip_prefix('+') {
add = true;
s = rest;
}
let (fchar, fnam): (u8, &str) = if prefchar != 0 { (prefchar, s) } else {
let bytes = s.as_bytes();
if bytes.len() >= 2 && bytes[1] == b':' {
(bytes[0], &s[2..])
} else {
(b'b', s) }
};
let modname = match module {
Some(m) => m,
None => { ret = 1; continue; }
};
if add {
match fchar {
b'b' => { table.autoload_builtins.insert(fnam.to_string(), modname.to_string()); }
b'c' | b'C' => { table.autoload_conditions.insert(fnam.to_string(), modname.to_string()); }
b'p' => { table.autoload_params.insert(fnam.to_string(), modname.to_string()); }
b'f' => { table.autoload_mathfuncs.insert(fnam.to_string(), modname.to_string()); }
_ => { ret = 1; }
}
} else {
match fchar {
b'b' => { table.autoload_builtins.remove(fnam); }
b'c' | b'C' => { table.autoload_conditions.remove(fnam); }
b'p' => { table.autoload_params.remove(fnam); }
b'f' => { table.autoload_mathfuncs.remove(fnam); }
_ => { ret = 1; }
}
}
}
ret
}
pub fn autoloadscan(name: &str, optstr: &str, flags: u32, printflags: i32) { if (flags & BINF_ADDED) != 0 { return; }
if (printflags & crate::ported::zsh_h::PRINT_LIST) != 0 { print!("zmodload -ab ");
if optstr.starts_with('-') { print!("-- "); }
print!("{}", optstr); if name != optstr { print!(" "); print!("{}", name); }
} else {
print!("{}", name); if name != optstr { print!(" ("); print!("{}", optstr); print!(")"); }
}
println!(); }
pub fn bin_zmodload(nam: &str, args: &[String], ops: &crate::ported::zsh_h::options, _func: i32) -> i32 {
let mut table = MODULESTAB.lock().unwrap();
let table = &mut *table;
let ops_bcpf = OPT_ISSET(ops, b'b') || OPT_ISSET(ops, b'c') || OPT_ISSET(ops, b'p') || OPT_ISSET(ops, b'f');
let ops_au = OPT_ISSET(ops, b'a') || OPT_ISSET(ops, b'u'); let mut ret: i32;
if ops_bcpf && !ops_au { zwarnnam(nam, "-b, -c, -f, and -p must be combined with -a or -u"); return 1; }
if OPT_ISSET(ops, b'F') && (ops_bcpf || OPT_ISSET(ops, b'u')) { zwarnnam(nam, "-b, -c, -f, -p and -u cannot be combined with -F"); return 1; }
if OPT_ISSET(ops, b'A') || OPT_ISSET(ops, b'R') { if ops_bcpf || ops_au || OPT_ISSET(ops, b'd') || (OPT_ISSET(ops, b'R') && OPT_ISSET(ops, b'e'))
{
zwarnnam(nam, "illegal flags combined with -A or -R"); return 1; }
if !OPT_ISSET(ops, b'e') { return bin_zmodload_alias(table, nam, args, ops); }
}
if OPT_ISSET(ops, b'd') && OPT_ISSET(ops, b'a') { zwarnnam(nam, "-d cannot be combined with -a"); return 1; }
if OPT_ISSET(ops, b'u') && args.is_empty() { zwarnnam(nam, "what do you want to unload?"); return 1; }
if OPT_ISSET(ops, b'e') && (OPT_ISSET(ops, b'I') || OPT_ISSET(ops, b'L') || (OPT_ISSET(ops, b'a') && !OPT_ISSET(ops, b'F'))
|| OPT_ISSET(ops, b'd') || OPT_ISSET(ops, b'i')
|| OPT_ISSET(ops, b'u'))
{
zwarnnam(nam, "-e cannot be combined with other options"); return 1; }
for fp in [b'l', b'P'] { if OPT_ISSET(ops, fp) && !OPT_ISSET(ops, b'F') { zwarnnam(nam, &format!("-{} is only allowed with -F", fp as char)); return 1; }
}
crate::ported::mem::queue_signals(); if OPT_ISSET(ops, b'F') { ret = bin_zmodload_features(table, nam, args, ops); } else if OPT_ISSET(ops, b'e') { ret = bin_zmodload_exist(table, nam, args, ops); } else if OPT_ISSET(ops, b'd') { ret = bin_zmodload_dep(table, nam, args, ops); } else {
let autoopts = (OPT_ISSET(ops, b'b') as i32) + (OPT_ISSET(ops, b'c') as i32)
+ (OPT_ISSET(ops, b'p') as i32)
+ (OPT_ISSET(ops, b'f') as i32);
if autoopts != 0 || OPT_ISSET(ops, b'a') { if autoopts > 1 { zwarnnam(nam, "use only one of -b, -c, or -p"); ret = 1; } else {
ret = bin_zmodload_auto(table, nam, args, ops); }
} else {
ret = bin_zmodload_load(table, nam, args, ops); }
}
crate::ported::mem::unqueue_signals(); ret }
pub fn bin_zmodload_alias(table: &mut modulestab, nam: &str, args: &[String], ops: &crate::ported::zsh_h::options) -> i32 {
if args.is_empty() {
if crate::ported::zsh_h::OPT_ISSET(ops, b'R') { crate::ported::utils::zwarnnam(nam, "no module alias to remove"); return 1; }
for (name, m) in &table.modules {
if (m.node.flags & crate::ported::zsh_h::MOD_ALIAS) != 0 {
if crate::ported::zsh_h::OPT_ISSET(ops, b'L') {
println!("zmodload -A {}={}", name, m.alias.as_deref().unwrap_or(""));
} else {
println!("{} -> {}", name, m.alias.as_deref().unwrap_or(""));
}
}
}
return 0; }
for arg in args {
let (lhs, aliasname): (&str, Option<&str>) = match arg.find('=') {
Some(eq) => (&arg[..eq], Some(&arg[eq+1..])),
None => (arg.as_str(), None),
};
if modname_ok(lhs) == 0 { crate::ported::utils::zwarnnam(nam, &format!("invalid module name `{}'", lhs)); return 1; }
if crate::ported::zsh_h::OPT_ISSET(ops, b'R') { if aliasname.is_some() { crate::ported::utils::zwarnnam(nam,
&format!("bad syntax for removing module alias: {}", lhs)); return 1; }
match table.modules.get(lhs) {
Some(m) => {
if (m.node.flags & crate::ported::zsh_h::MOD_ALIAS) == 0 { crate::ported::utils::zwarnnam(nam,
&format!("module is not an alias: {}", lhs)); return 1; }
table.modules.remove(lhs); }
None => {
crate::ported::utils::zwarnnam(nam,
&format!("no such module alias: {}", lhs)); return 1; }
}
} else {
if let Some(target) = aliasname { if modname_ok(target) == 0 { crate::ported::utils::zwarnnam(nam,
&format!("invalid module name `{}'", target)); return 1; }
let mut mname = target;
let mut depth = 0;
loop {
if depth > 256 { break; }
depth += 1;
if mname == lhs { crate::ported::utils::zwarnnam(nam,
&format!("module alias would refer to itself: {}", lhs)); return 1; }
match table.modules.get(mname) {
Some(m) if (m.node.flags & crate::ported::zsh_h::MOD_ALIAS) != 0 => {
mname = m.alias.as_deref().unwrap_or("");
}
_ => break,
}
}
if let Some(m) = table.modules.get_mut(lhs) {
if (m.node.flags & crate::ported::zsh_h::MOD_ALIAS) == 0 { crate::ported::utils::zwarnnam(nam,
&format!("module is not an alias: {}", lhs)); return 1; }
m.alias = Some(target.to_string()); } else {
let mut m = module::new(lhs); m.node.flags = crate::ported::zsh_h::MOD_ALIAS; m.alias = Some(target.to_string()); table.modules.insert(lhs.to_string(), m); }
} else {
match table.modules.get(lhs) {
Some(m) if (m.node.flags & crate::ported::zsh_h::MOD_ALIAS) != 0 => {
if crate::ported::zsh_h::OPT_ISSET(ops, b'L') {
println!("zmodload -A {}={}", lhs, m.alias.as_deref().unwrap_or(""));
} else {
println!("{} -> {}", lhs, m.alias.as_deref().unwrap_or(""));
}
}
Some(_) => {
crate::ported::utils::zwarnnam(nam,
&format!("module is not an alias: {}", lhs)); return 1; }
None => {
crate::ported::utils::zwarnnam(nam,
&format!("no such module alias: {}", lhs)); return 1; }
}
}
}
}
0 }
pub fn bin_zmodload_auto(table: &mut modulestab, _nam: &str, args: &[String], ops: &crate::ported::zsh_h::options) -> i32 { let fchar: char; let _flags: i32 = if crate::ported::zsh_h::OPT_ISSET(ops, b'i') { FEAT_IGNORE } else { 0 };
if crate::ported::zsh_h::OPT_ISSET(ops, b'c') {
fchar = if crate::ported::zsh_h::OPT_ISSET(ops, b'I') { 'C' } else { 'c' };
let _ = fchar;
if args.is_empty() { for (name, module) in &table.autoload_conditions {
println!("{} {}", module, name);
}
return 0;
}
} else if crate::ported::zsh_h::OPT_ISSET(ops, b'p') { if args.is_empty() {
for (name, module) in &table.autoload_params {
println!("{} {}", module, name);
}
return 0;
}
} else if crate::ported::zsh_h::OPT_ISSET(ops, b'f') { if args.is_empty() {
for (name, module) in &table.autoload_mathfuncs {
println!("{} {}", module, name);
}
return 0;
}
} else {
if args.is_empty() {
for (name, module) in &table.autoload_builtins {
autoloadscan(name, module, 0,
if crate::ported::zsh_h::OPT_ISSET(ops, b'L') {
crate::ported::zsh_h::PRINT_LIST
} else { 0 });
}
return 0;
}
}
if args.len() < 2 { return 1; }
let modnam = &args[0]; for nm in &args[1..] {
if crate::ported::zsh_h::OPT_ISSET(ops, b'p') {
table.autoload_params.insert(nm.clone(), modnam.clone());
} else if crate::ported::zsh_h::OPT_ISSET(ops, b'f') {
table.autoload_mathfuncs.insert(nm.clone(), modnam.clone());
} else if crate::ported::zsh_h::OPT_ISSET(ops, b'c') {
table.autoload_conditions.insert(nm.clone(), modnam.clone());
} else {
table.autoload_builtins.insert(nm.clone(), modnam.clone());
}
}
0 }
pub fn bin_zmodload_dep(table: &mut modulestab, _nam: &str, args: &[String], ops: &crate::ported::zsh_h::options) -> i32 { if crate::ported::zsh_h::OPT_ISSET(ops, b'u') { if args.is_empty() { return 0; }
let tnam = &args[0];
let rest = &args[1..];
let canon = match find_module(table, tnam, FINDMOD_ALIASP) {
Some(n) => n,
None => return 0, };
if let Some(m) = table.modules.get_mut(&canon) {
if let Some(deps) = m.deps.as_mut() { if !rest.is_empty() {
for to_remove in rest {
if let Some(pos) = deps.iter().position(|d| d == to_remove) {
deps.delete_node(pos); }
}
} else {
deps.clear();
}
}
let no_deps_no_handle = m.deps.as_ref().map_or(true, |d| d.is_empty());
if no_deps_no_handle {
table.modules.remove(&canon);
}
}
return 0; }
if args.len() < 2 {
for (name, m) in &table.modules {
if let Some(deps) = m.deps.as_ref() {
if !deps.is_empty() {
let joined: Vec<&str> = deps.iter().map(|s| s.as_str()).collect();
println!("zmodload -d {} {}", name, joined.join(" "));
}
}
}
return 0;
}
let target = &args[0];
for dep in &args[1..] {
add_dep(table, target, dep); }
0
}
pub fn bin_zmodload_exist(table: &mut modulestab, _nam: &str, args: &[String], _ops: &crate::ported::zsh_h::options) -> i32 { if args.is_empty() { for (name, _) in &table.modules {
println!("{}", name);
}
return 0; }
let mut ret: i32 = 0;
for arg in args { if ret != 0 { break; }
if find_module(table, arg, FINDMOD_ALIASP).is_none() { ret = 1; }
}
ret }
pub fn bin_zmodload_features(table: &mut modulestab, nam: &str, args: &[String], ops: &crate::ported::zsh_h::options) -> i32 { let modname = args.first(); let rest_args = if args.is_empty() { &args[..] } else { &args[1..] };
if modname.is_none() {
if crate::ported::zsh_h::OPT_ISSET(ops, b'L') { if crate::ported::zsh_h::OPT_ISSET(ops, b'P') { crate::ported::utils::zwarnnam(nam, "-P is only allowed with a module name"); return 1; }
for (name, _m) in &table.modules {
println!("zmodload -F {}", name);
}
return 0; }
crate::ported::utils::zwarnnam(nam, "-F requires a module name"); return 1; }
let modname = modname.unwrap();
let mut feats: Vec<String> = Vec::with_capacity(rest_args.len());
for arg in rest_args {
feats.push(arg.clone());
}
if !feats.is_empty() {
autofeatures(table, nam, Some(modname), &feats, 0, 0);
}
do_module_features(table, modname, FEAT_CHECKAUTO); 0
}
pub fn bin_zmodload_load(table: &mut modulestab, nam: &str, args: &[String], ops: &crate::ported::zsh_h::options) -> i32 { let mut ret: i32 = 0;
if crate::ported::zsh_h::OPT_ISSET(ops, b'u') { for arg in args {
if unload_named_module(table, arg, nam, crate::ported::zsh_h::OPT_ISSET(ops, b'i') as i32) != 0 {
ret = 1;
}
}
return ret; } else if args.is_empty() { for (name, _m) in &table.modules {
println!("{}", name);
}
return 0; } else {
for arg in args {
let tmpret = require_module(table, arg, None); if tmpret != 0 && ret != 1 { ret = tmpret;
}
}
ret
}
}
#[allow(unused_variables)]
pub fn boot_(m: *const crate::ported::zsh_h::module) -> i32 { 0 }
pub fn boot_module(_table: &mut modulestab, _name: &str) -> i32 { 0 }
#[allow(unused_variables)]
pub fn checkaddparam(nam: &str, opt_i: i32) -> i32 { 0
}
#[allow(unused_variables)]
pub fn cleanup_(m: *const crate::ported::zsh_h::module) -> i32 { 0 }
pub fn cleanup_module(_table: &mut modulestab, _name: &str) -> i32 { 0 }
pub fn del_automathfunc(table: &mut modulestab, _modnam: &str, fnam: &str, flags: i32) -> i32 { if !table.autoload_mathfuncs.contains_key(fnam) { if (flags & FEAT_IGNORE) == 0 { return 2; }
} else {
table.autoload_mathfuncs.remove(fnam);
}
0 }
pub fn delete_module(table: &mut modulestab, name: &str) -> i32 { table.modules.remove(name); 0
}
pub fn deletehookdeffunc(table: &mut modulestab, h: &mut crate::ported::zsh_h::hookdef, fn_name: &str) -> i32 { if let Some(funcs) = table.hooks.get_mut(&h.name) {
if let Some(pos) = funcs.iter().position(|n| n == fn_name) {
funcs.remove(pos); let _ = h.funcs;
return 0; }
}
let _ = h.funcs;
1 }
pub fn do_boot_module(m: &mut modulestab, enablesarr: &str, silent: i32) -> i32 { let flags = if silent != 0 { FEAT_IGNORE | FEAT_CHECKAUTO
} else {
FEAT_CHECKAUTO };
let ret = do_module_features(m, enablesarr, flags); if ret == 1 { return 1; }
if boot_module(m, enablesarr) != 0 { return 1; }
ret }
pub fn do_cleanup_module(table: &mut modulestab, name: &str) -> i32 { if table.modules.contains_key(name) { cleanup_module(table, name) } else {
0
}
}
pub fn do_load_module(table: &mut modulestab, name: &str, silent: i32) -> i32 { let ret = try_load_module(table, name);
if ret == 0 && silent == 0 { crate::ported::utils::zwarn(&format!("failed to load module: {}", name));
}
ret }
pub fn do_module_features(m: &mut modulestab, enablesarr: &str, flags: i32) -> i32 { let mut features: Vec<String> = Vec::new(); let mut ret: i32 = 0;
if features_module(m, enablesarr, &mut features) == 0 {
let mut enables: Option<Vec<i32>> = None;
if enables_module(m, enablesarr, &mut enables) != 0 { if (flags & FEAT_IGNORE) == 0 { crate::ported::utils::zwarn(&format!(
"error getting enabled features for module `{}'", enablesarr,
));
}
return 1; }
if (flags & FEAT_CHECKAUTO) != 0 {
let autoloads: Vec<String> = match m.modules.get(enablesarr) {
Some(m) => m
.autoloads
.as_ref()
.map(|al| al.iter().cloned().collect())
.unwrap_or_default(),
None => return ret,
};
for al in &autoloads { let found = features.iter().any(|f| f == al);
if !found { if (flags & FEAT_IGNORE) == 0 { crate::ported::utils::zwarn(&format!(
"module `{}' has no such feature: `{}': autoload cancelled", enablesarr, al,
));
}
let arg = vec![al.clone()];
autofeatures(m, "", Some(enablesarr), &arg, 0, FEAT_IGNORE | FEAT_REMOVE);
}
}
}
}
ret }
#[allow(unused_variables)]
pub fn dyn_boot_module(m: *const crate::ported::zsh_h::module) -> i32 { 0 }
#[allow(unused_variables)]
pub fn dyn_cleanup_module(m: *const crate::ported::zsh_h::module) -> i32 { 0 }
#[allow(unused_variables)]
pub fn dyn_enables_module(m: *const crate::ported::zsh_h::module, enables: &mut Option<Vec<i32>>) -> i32 { 0 }
#[allow(unused_variables)]
pub fn dyn_features_module(m: *const crate::ported::zsh_h::module, features: &mut Vec<String>) -> i32 { 0 }
#[allow(unused_variables)]
pub fn dyn_finish_module(m: *const crate::ported::zsh_h::module) -> i32 { 0 }
#[allow(unused_variables)]
pub fn dyn_setup_module(m: *const crate::ported::zsh_h::module) -> i32 { 0 }
#[allow(unused_variables)]
pub fn enables_(m: *const crate::ported::zsh_h::module, enables: &mut Option<Vec<i32>>) -> i32 { 1 }
pub fn enables_module(_table: &mut modulestab, _name: &str, _enables: &mut Option<Vec<i32>>) -> i32 { 0 }
#[allow(unused_variables)]
pub fn features_(m: *const crate::ported::zsh_h::module, features: &mut Vec<String>) -> i32 { 1 }
pub fn features_module(_table: &mut modulestab, _name: &str, _features: &mut Vec<String>) -> i32 { 0 }
pub const FINDMOD_ALIASP: i32 = 0x0001;
pub const FINDMOD_CREATE: i32 = 0x0002;
pub fn find_module(table: &mut modulestab, name: &str, flags: i32) -> Option<String> { let mut cur_name = name.to_string();
let mut depth = 0;
loop {
if depth > 64 { return None; } depth += 1;
match table.modules.get(&cur_name) {
Some(m) => {
if (flags & FINDMOD_ALIASP) != 0 && (m.node.flags & crate::ported::zsh_h::MOD_ALIAS) != 0 {
if let Some(target) = m.alias.clone() {
cur_name = target;
continue;
}
return None;
}
return Some(cur_name);
}
None => {
if (flags & FINDMOD_CREATE) == 0 {
return None;
}
table.modules.insert(cur_name.clone(), module::new(&cur_name));
return Some(cur_name);
}
}
}
}
#[allow(unused_variables)]
pub fn finish_(m: *const crate::ported::zsh_h::module) -> i32 { 0 }
pub fn finish_module(_table: &mut modulestab, _name: &str) -> i32 { 0 }
pub fn getmathfunc(table: &mut modulestab, name: &str, autol: i32) -> Option<String> { if let Some(module) = table.autoload_mathfuncs.get(name).cloned() { if autol != 0 { let _ = ensurefeature(table, &module, "f:", Some(name));
return table.autoload_mathfuncs.get(name).cloned();
}
return Some(module); }
None }
#[allow(unused_variables)]
pub fn hpux_dlsym(handle: usize, name: &str) -> usize { 0 }
pub fn load_and_bind(_fn_path: &str) -> usize { 0 }
pub fn modname_ok(p: &str) -> i32 { let bytes = p.as_bytes();
let mut i: usize = 0;
loop {
while i < bytes.len() {
let b = bytes[i];
if b.is_ascii_alphanumeric() || b == b'_' { i += 1; } else { break; }
}
if i >= bytes.len() { return 1; }
if bytes[i] != b'/' { break; } i += 1;
}
0 }
#[allow(unused_variables)]
pub fn module_func(m: &module, name: &str) -> usize { 0 }
pub fn module_loaded(table: &modulestab, name: &str) -> i32 { if table.modules.contains_key(name) { 1 } else {
0
}
}
pub fn printautoparams(name: &str, module: &str, flags: u32, lon: i32) { if (flags & crate::ported::zsh_h::PM_AUTOLOAD) != 0 { if lon != 0 { println!("zmodload -ap {} {}", module, name);
} else {
println!("{} ({})", name, module);
}
}
}
pub fn require_module(table: &mut modulestab, modname: &str, _features: Option<&[String]>) -> i32 {
if try_load_module(table, modname) == 0 {
return 1;
}
0
}
pub fn ensurefeature(table: &mut modulestab, modname: &str, prefix: &str, feature: Option<&str>) -> i32 { match feature {
None => require_module(table, modname, None), Some(f) => {
let combined = crate::ported::string::dyncat(prefix, f); let arr = vec![combined];
require_module(table, modname, Some(&arr)) }
}
}
#[allow(unused_variables)]
pub fn setup_(m: *const crate::ported::zsh_h::module) -> i32 { 0 }
pub fn setup_module(_table: &mut modulestab, _name: &str) -> i32 { 0 }
pub fn try_load_module(table: &modulestab, name: &str) -> i32 { if table.modules.contains_key(name) { 1 } else { 0 }
}
pub fn unload_named_module(table: &mut modulestab, name: &str, _nam: &str, _silent: i32) -> i32 {
if table.modules.remove(name).is_some() {
0
} else {
1
}
}