#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]
#![allow(non_snake_case)]
use std::sync::{Mutex, OnceLock};
use std::sync::atomic::{AtomicI32, AtomicI64, Ordering};
use crate::ported::signals_h::{queue_signals, unqueue_signals};
use crate::ported::string::dupstring;
use crate::ported::ztype_h::INAMESPC;
use crate::ported::zsh_h::{
eprog, funcwrap, module, param, EMULATE_KSH, EMULATION,
PM_LOCAL, PM_NAMEREF, PM_READONLY, PM_UNSET,
};
use crate::ported::zsh_h::{PM_NAMEREF as PMN, PARAMDEF};
#[allow(unused_variables)]
pub fn edcharsetfn(pm: *mut param, x: *mut libc::c_char) { }
pub fn matchgetfn(pm: *mut param) -> Vec<String> { let zsh_match: Vec<String> = crate::ported::params::paramtab().read().ok()
.and_then(|t| t.get("match").and_then(|p| p.u_arr.clone()))
.unwrap_or_default();
if !pm.is_null() {
unsafe { (*pm).u_arr = None; } }
if !zsh_match.is_empty() { if crate::ported::zsh_h::isset(KSHARRAYS) { let match_str: String = crate::ported::params::paramtab().read().ok()
.and_then(|t| t.get("MATCH").and_then(|p| p.u_str.clone()))
.unwrap_or_default();
let mut ap: Vec<String> = Vec::with_capacity(zsh_match.len() + 1);
ap.push(crate::ported::utils::ztrdup(&match_str)); for s in &zsh_match { ap.push(crate::ported::utils::ztrdup(s));
}
if !pm.is_null() {
unsafe { (*pm).u_arr = Some(ap.clone()); }
}
ap
} else {
let dup: Vec<String> = zsh_match.iter()
.map(|s| crate::ported::utils::ztrdup(s))
.collect();
if !pm.is_null() {
unsafe { (*pm).u_arr = Some(dup.clone()); }
}
dup }
} else if crate::ported::zsh_h::isset(KSHARRAYS) { let match_str: String = crate::ported::params::paramtab().read().ok()
.and_then(|t| t.get("MATCH").and_then(|p| p.u_str.clone()))
.unwrap_or_default();
let one = vec![crate::ported::utils::ztrdup(&match_str)];
if !pm.is_null() {
unsafe { (*pm).u_arr = Some(one.clone()); }
}
one } else {
if !pm.is_null() {
unsafe { (*pm).u_arr = None; }
}
Vec::new() }
}
pub static sh_unsetval: [u8; 2] = [0, 0];
pub static sh_name: Mutex<String> = Mutex::new(String::new());
pub static sh_subscript: Mutex<String> = Mutex::new(String::new());
pub static sh_edchar: Mutex<String> = Mutex::new(String::new());
pub static sh_edmode: Mutex<[u8; 2]> = Mutex::new([0, 0]);
#[allow(dead_code)]
const LOCAL_NAMEREF: u32 = PM_LOCAL | PM_UNSET | PM_NAMEREF;
#[allow(unused_variables)]
pub fn ksh93_wrapper(prog: *const eprog, w: *const funcwrap, name: *mut libc::c_char) -> i32 { let mut f: *const crate::ported::zsh_h::funcstack;
let mut pm: *mut param;
let mut num: i64 = if (*funcstack.lock().unwrap()) != 0 {
crate::ported::params::paramtab().read().ok()
.and_then(|t| t.get(".sh.level")
.and_then(|p| p.u_str.as_ref().and_then(|s| s.parse::<i64>().ok())))
.unwrap_or(0)
} else { 0 };
if !EMULATION(EMULATE_KSH) { return 1; }
if num == 0 { f = (*funcstack.lock().unwrap()) as *const crate::ported::zsh_h::funcstack;
while !f.is_null() {
f = std::ptr::null_mut();
num += 1;
}
} else { num += 1; }
queue_signals(); locallevel.fetch_add(1, Ordering::SeqCst);
pm = crate::ported::params::createparam(".sh.command", LOCAL_NAMEREF as i32)
.map(Box::into_raw).unwrap_or(std::ptr::null_mut());
if !pm.is_null() {
unsafe { (*pm).level = locallevel.load(Ordering::Relaxed); } crate::ported::params::setloopvar(".sh.command", "ZSH_DEBUG_CMD"); unsafe { (*pm).node.flags |= PM_READONLY as i32; } }
if crate::ported::builtins::sched::zleactive.load(Ordering::Relaxed) != 0 {
pm = crate::ported::params::createparam(".sh.edcol", LOCAL_NAMEREF as i32) .map(Box::into_raw).unwrap_or(std::ptr::null_mut());
if !pm.is_null() {
unsafe { (*pm).level = locallevel.load(Ordering::Relaxed); } crate::ported::params::setloopvar(".sh.edcol", "CURSOR"); unsafe { (*pm).node.flags |= (PM_NAMEREF | PM_READONLY) as i32; } }
}
if crate::ported::builtins::sched::zleactive.load(Ordering::Relaxed) != 0 {
pm = crate::ported::params::createparam(".sh.edtext", LOCAL_NAMEREF as i32) .map(Box::into_raw).unwrap_or(std::ptr::null_mut());
if !pm.is_null() {
unsafe { (*pm).level = locallevel.load(Ordering::Relaxed); } crate::ported::params::setloopvar(".sh.edtext", "BUFFER"); unsafe { (*pm).node.flags |= PM_READONLY as i32; } }
}
pm = crate::ported::params::createparam(".sh.fun", (PM_LOCAL | PM_UNSET) as i32)
.map(Box::into_raw).unwrap_or(std::ptr::null_mut());
if !pm.is_null() {
unsafe { (*pm).level = locallevel.load(Ordering::Relaxed); } let name_str: String = if name.is_null() {
String::new()
} else {
unsafe { std::ffi::CStr::from_ptr(name).to_string_lossy().into_owned() }
};
crate::ported::params::setsparam(".sh.fun", &crate::ported::utils::ztrdup(&name_str));
unsafe { (*pm).node.flags |= PM_READONLY as i32; } }
pm = crate::ported::params::createparam(".sh.level", (PM_LOCAL | PM_UNSET) as i32)
.map(Box::into_raw).unwrap_or(std::ptr::null_mut());
if !pm.is_null() {
unsafe { (*pm).level = locallevel.load(Ordering::Relaxed); } crate::ported::params::setiparam(".sh.level", num); }
if crate::ported::builtins::sched::zleactive.load(Ordering::Relaxed) != 0 { let curkmap = curkeymapname.lock().unwrap().clone();
if !curkmap.is_empty() && crate::ported::zsh_h::isset(VIMODE) && curkmap == "main" { let mut em = sh_edmode.lock().unwrap();
em[0] = 0o33;
em[1] = 0;
} else {
let mut em = sh_edmode.lock().unwrap();
em[0] = 0;
em[1] = 0;
}
let edch_unset = sh_edchar.lock().unwrap().is_empty();
if edch_unset {
let keys: String = crate::ported::params::paramtab().read().ok()
.and_then(|t| t.get("KEYS").and_then(|p| p.u_str.clone()))
.unwrap_or_default();
*sh_edchar.lock().unwrap() = dupstring(&keys);
}
let varedarg_val = varedarg.lock().unwrap().clone();
if !varedarg_val.is_empty() { *sh_name.lock().unwrap() = dupstring(&varedarg_val);
let nm = sh_name.lock().unwrap().clone();
let _ = INAMESPC;
let ie_off = {
let mut k = 0;
for &b in nm.as_bytes() {
match b {
b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'_' => k += 1,
_ => break,
}
}
k
};
if ie_off < nm.len() { let head = &nm[..ie_off];
let tail = &nm[ie_off + 1..]; *sh_name.lock().unwrap() = head.to_string();
*sh_subscript.lock().unwrap() = dupstring(tail);
let mut sub = sh_subscript.lock().unwrap();
if sub.ends_with(']') { sub.pop(); }
} else {
sh_subscript.lock().unwrap().clear();
}
pm = crate::ported::params::createparam(".sh.value", LOCAL_NAMEREF as i32)
.map(Box::into_raw).unwrap_or(std::ptr::null_mut());
if !pm.is_null() {
unsafe { (*pm).level = locallevel.load(Ordering::Relaxed); } crate::ported::params::setloopvar(".sh.value", "BUFFER"); unsafe { (*pm).node.flags |= PM_READONLY as i32; } }
} else {
sh_name.lock().unwrap().clear();
sh_subscript.lock().unwrap().clear();
}
} else {
sh_edchar.lock().unwrap().clear();
sh_name.lock().unwrap().clear();
sh_subscript.lock().unwrap().clear();
let mut em = sh_edmode.lock().unwrap();
em[0] = 0;
em[1] = 0;
}
locallevel.fetch_sub(1, Ordering::SeqCst); unqueue_signals();
1 }
#[allow(unused_variables)]
pub fn setup_(m: *const module) -> i32 { 0
}
pub fn features_(m: *const module, features: &mut Vec<String>) -> i32 { *features = featuresarray(m, module_features());
0 }
pub fn enables_(m: *const module, enables: &mut Option<Vec<i32>>) -> i32 { handlefeatures(m, module_features(), enables) }
pub fn boot_(m: *const module) -> i32 {
let _ = m;
0
}
pub fn cleanup_(m: *const module) -> i32 {
let mut p: usize;
let partab: [crate::ported::zsh_h::paramdef; 9] = [
PARAMDEF(".sh.edchar", (PM_SCALAR | PM_SPECIAL) as i32, 0, 0), PARAMDEF(".sh.edmode", (PM_SCALAR | PM_READONLY | PM_SPECIAL) as i32, 0, 0), PARAMDEF(".sh.file", (PMN | PM_READONLY) as i32, 0, 0), PARAMDEF(".sh.lineno", (PMN | PM_READONLY) as i32, 0, 0), PARAMDEF(".sh.match", (PM_ARRAY | PM_READONLY) as i32, 0, 0), PARAMDEF(".sh.name", (PM_SCALAR | PM_READONLY | PM_SPECIAL) as i32, 0, 0), PARAMDEF(".sh.subscript", (PM_SCALAR | PM_READONLY | PM_SPECIAL) as i32, 0, 0), PARAMDEF(".sh.subshell", (PMN | PM_READONLY) as i32, 0, 0), PARAMDEF(".sh.version", (PMN | PM_READONLY) as i32, 0, 0), ];
p = 0;
while p < partab.len() { let entry = &partab[p];
if (entry.flags as u32 & PM_NAMEREF) != 0 { if let Ok(mut t) = crate::ported::params::paramtab().write() {
if let Some(pm) = t.get_mut(&entry.name) {
pm.node.flags &= !(PM_NAMEREF as i32); }
}
}
p += 1;
}
setfeatureenables(m, module_features(), None) }
use crate::ported::zsh_h::features as features_t;
static MODULE_FEATURES: OnceLock<Mutex<features_t>> = OnceLock::new();
fn module_features() -> &'static Mutex<features_t> {
MODULE_FEATURES.get_or_init(|| Mutex::new(features_t {
bn_list: None,
bn_size: 1, cd_list: None,
cd_size: 0,
mf_list: None,
mf_size: 0,
pd_list: None,
pd_size: 9, n_abstract: 0,
}))
}
fn featuresarray(_m: *const module, _f: &Mutex<features_t>) -> Vec<String> {
vec![
"b:nameref".to_string(),
"p:.sh.edchar".to_string(),
"p:.sh.edmode".to_string(),
"p:.sh.file".to_string(),
"p:.sh.lineno".to_string(),
"p:.sh.match".to_string(),
"p:.sh.name".to_string(),
"p:.sh.subscript".to_string(),
"p:.sh.subshell".to_string(),
"p:.sh.version".to_string(),
]
}
fn handlefeatures(
_m: *const module,
_f: &Mutex<features_t>,
enables: &mut Option<Vec<i32>>,
) -> i32 {
if enables.is_none() {
*enables = Some(vec![1; 10]);
}
0
}
fn setfeatureenables(
_m: *const module,
_f: &Mutex<features_t>,
_e: Option<&[i32]>,
) -> i32 {
0
}
const PM_SCALAR: u32 = crate::ported::zsh_h::PM_SCALAR;
const PM_ARRAY: u32 = crate::ported::zsh_h::PM_ARRAY;
const PM_SPECIAL: u32 = crate::ported::zsh_h::PM_SPECIAL;
#[allow(unused_variables)]
pub fn finish_(m: *const module) -> i32 { 0
}
pub use crate::ported::options::emulation;
pub use crate::ported::params::locallevel;
pub static curkeymapname: Mutex<String> = Mutex::new(String::new());
pub static varedarg: Mutex<String> = Mutex::new(String::new());
static funcstack: Mutex<usize> = Mutex::new(0);
const KSHARRAYS: i32 = crate::ported::zsh_h::KSHARRAYS;
const VIMODE: i32 = crate::ported::zsh_h::VIMODE;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ksh93_wrapper_returns_one_when_not_emulate_ksh() {
emulation.store(0, Ordering::SeqCst);
let rc = ksh93_wrapper(
std::ptr::null(),
std::ptr::null(),
std::ptr::null_mut(),
);
assert_eq!(rc, 1);
}
#[test]
fn ksh93_wrapper_runs_full_body_under_emulate_ksh() {
let saved = emulation.load(Ordering::SeqCst);
emulation.store(EMULATE_KSH, Ordering::SeqCst);
let rc = ksh93_wrapper(
std::ptr::null(),
std::ptr::null(),
std::ptr::null_mut(),
);
assert_eq!(rc, 1);
assert_eq!(locallevel.load(Ordering::SeqCst), 0);
emulation.store(saved, Ordering::SeqCst);
}
#[test]
fn matchgetfn_empty_returns_empty() {
let v = matchgetfn(std::ptr::null_mut());
assert!(v.is_empty());
}
#[test]
fn edcharsetfn_noop() {
edcharsetfn(std::ptr::null_mut(), std::ptr::null_mut());
}
#[test]
fn module_loaders_return_zero() {
let m: *const module = std::ptr::null();
assert_eq!(setup_(m), 0);
let mut features = Vec::new();
assert_eq!(features_(m, &mut features), 0);
let mut enables: Option<Vec<i32>> = None;
assert_eq!(enables_(m, &mut enables), 0);
assert_eq!(boot_(m), 0);
assert_eq!(cleanup_(m), 0);
assert_eq!(finish_(m), 0);
}
#[test]
fn statics_default_to_unsetval() {
sh_name.lock().unwrap().clear();
sh_subscript.lock().unwrap().clear();
sh_edchar.lock().unwrap().clear();
*sh_edmode.lock().unwrap() = [0, 0];
assert!(sh_name.lock().unwrap().is_empty());
assert!(sh_subscript.lock().unwrap().is_empty());
assert!(sh_edchar.lock().unwrap().is_empty());
assert_eq!(*sh_edmode.lock().unwrap(), [0u8, 0u8]);
assert_eq!(sh_unsetval, [0u8, 0u8]);
}
#[test]
fn local_nameref_matches_c_define() {
assert_eq!(LOCAL_NAMEREF, PM_LOCAL | PM_UNSET | PM_NAMEREF);
}
}
#[allow(dead_code)]
const _: AtomicI64 = AtomicI64::new(0);