use crate::ported::utils::zwarnnam;
use crate::ported::zsh_h::OPT_ISSET;
use std::sync::atomic::Ordering;
#[derive(Debug, Clone, Copy)]
#[allow(non_camel_case_types)]
pub struct gsu_closure { pub kind: u8, pub g: usize, }
#[allow(unused_variables)]
pub fn makeprivate(hn: *mut crate::ported::zsh_h::param, flags: i32) { if hn.is_null() { return; }
let pm_level = unsafe { (*hn).level };
let cur_local = crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed);
if pm_level != cur_local { return; }
let pm_flags = unsafe { (*hn).node.flags };
let pm_ename = unsafe { (*hn).ename.is_some() };
let has_old = unsafe { (*hn).old.is_some() };
let pm_special = (pm_flags & crate::ported::zsh_h::PM_SPECIAL as i32) != 0;
let pm_removable = (pm_flags & crate::ported::zsh_h::PM_REMOVABLE as i32) != 0;
let pm_norestore = (pm_flags & crate::ported::zsh_h::PM_NORESTORE as i32) != 0;
let outer_cond = pm_ename
|| pm_norestore
|| (has_old && (
true
));
if outer_cond {
if pm_special && !pm_removable { crate::ported::utils::zerr(
&format!("can't change scope of existing param: {}",
unsafe { (*hn).node.nam.clone() }), );
}
MAKEPRIVATE_ERROR.store(1, std::sync::atomic::Ordering::Relaxed); return; }
let name = unsafe { (*hn).node.nam.clone() };
if let Ok(mut p) = PRIVATE_PARAMS.lock() {
p.insert(name);
}
unsafe {
(*hn).node.flags |= (crate::ported::zsh_h::PM_HIDE
| crate::ported::zsh_h::PM_SPECIAL
| crate::ported::zsh_h::PM_REMOVABLE
| crate::ported::zsh_h::PM_RO_BY_DESIGN) as i32;
}
unsafe { (*hn).level -= 1; }
}
pub static MAKEPRIVATE_ERROR: std::sync::atomic::AtomicI32 =
std::sync::atomic::AtomicI32::new(0);
pub fn is_private(pm: *const crate::ported::zsh_h::param) -> i32 { if pm.is_null() { return 0; }
let name = unsafe { (*pm).node.nam.clone() };
if PRIVATE_PARAMS.lock().map(|p| p.contains(&name)).unwrap_or(false) {
1 } else {
0 }
}
pub fn setfn_error(pm: *mut crate::ported::zsh_h::param) { if pm.is_null() { return; }
let name = unsafe {
(*pm).node.flags |= crate::ported::zsh_h::PM_UNSET as i32; (*pm).node.nam.clone()
};
crate::ported::utils::zerr(&format!( "{}: attempt to assign private in nested scope",
name,
));
}
pub static PRIVATE_PARAMS: std::sync::LazyLock<std::sync::Mutex<std::collections::HashSet<String>>>
= std::sync::LazyLock::new(|| std::sync::Mutex::new(std::collections::HashSet::new()));
pub static private_wraplevel: std::sync::atomic::AtomicI32
= std::sync::atomic::AtomicI32::new(0);
#[allow(unused_variables)]
pub fn printprivatenode(hn: *mut crate::ported::zsh_h::param, printflags: i32) { let mut cur = hn;
while !cur.is_null() {
let pm_level = unsafe { (*cur).level };
let pm_flags = unsafe { (*cur).node.flags };
let fakelvl = FAKELEVEL.load(std::sync::atomic::Ordering::Relaxed);
let unset_in_fake = fakelvl != 0
&& fakelvl > pm_level
&& (pm_flags & crate::ported::zsh_h::PM_UNSET as i32) != 0;
let cond = (fakelvl == 0 || unset_in_fake)
&& crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) > pm_level
&& is_private(cur) != 0;
if !cond { break; }
cur = unsafe { (*cur).old.as_ref().map(|b| b.as_ref() as *const _ as *mut _).unwrap_or(std::ptr::null_mut()) };
}
if !cur.is_null() {
let hn: &mut crate::ported::zsh_h::param = unsafe { &mut *cur };
crate::ported::params::printparamnode(hn, printflags); }
}
pub static FAKELEVEL: std::sync::atomic::AtomicI32 =
std::sync::atomic::AtomicI32::new(0);
pub fn pps_getfn(pm: *mut crate::ported::zsh_h::param) -> String { if pm.is_null() { return String::new(); }
let pm_level = unsafe { (*pm).level };
if crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) >= pm_level { unsafe { (*pm).u_str.clone().unwrap_or_default() }
} else {
String::new() }
}
pub fn pps_setfn(pm: *mut crate::ported::zsh_h::param, x: &str) { if pm.is_null() { return; }
let pm_level = unsafe { (*pm).level };
if crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) == pm_level
|| crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) > private_wraplevel.load(std::sync::atomic::Ordering::Relaxed) { unsafe { (*pm).u_str = Some(x.to_string()); } } else {
setfn_error(pm); }
}
pub fn pps_unsetfn(pm: *mut crate::ported::zsh_h::param, explicit: i32) { if pm.is_null() { return; }
let pm_level = unsafe { (*pm).level };
if crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) <= pm_level { unsafe { (*pm).u_str = None; }
}
if explicit != 0 { unsafe { (*pm).node.flags |= crate::ported::zsh_h::PM_DECLARED as i32; } } else {
if let Ok(mut p) = PRIVATE_PARAMS.lock() {
unsafe { p.remove(&(*pm).node.nam); }
}
}
}
pub fn ppi_getfn(pm: *mut crate::ported::zsh_h::param) -> i64 { if pm.is_null() { return 0; }
let pm_level = unsafe { (*pm).level };
if crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) >= pm_level { unsafe { (*pm).u_val } } else {
0 }
}
pub fn ppi_setfn(pm: *mut crate::ported::zsh_h::param, x: i64) { if pm.is_null() { return; }
let pm_level = unsafe { (*pm).level };
if crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) == pm_level
|| crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) > private_wraplevel.load(std::sync::atomic::Ordering::Relaxed) {
unsafe { (*pm).u_val = x; } } else {
setfn_error(pm); }
}
pub fn ppi_unsetfn(pm: *mut crate::ported::zsh_h::param, explicit: i32) { if pm.is_null() { return; }
let pm_level = unsafe { (*pm).level };
if crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) <= pm_level { unsafe { (*pm).u_val = 0; } }
if explicit != 0 { unsafe { (*pm).node.flags |= crate::ported::zsh_h::PM_DECLARED as i32; } } else {
if let Ok(mut p) = PRIVATE_PARAMS.lock() {
unsafe { p.remove(&(*pm).node.nam); }
}
}
}
pub fn ppf_getfn(pm: *mut crate::ported::zsh_h::param) -> f64 { if pm.is_null() { return 0.0; }
let pm_level = unsafe { (*pm).level };
if crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) >= pm_level { unsafe { (*pm).u_dval } } else {
0.0 }
}
pub fn ppf_setfn(pm: *mut crate::ported::zsh_h::param, x: f64) { if pm.is_null() { return; }
let pm_level = unsafe { (*pm).level };
if crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) == pm_level
|| crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) > private_wraplevel.load(std::sync::atomic::Ordering::Relaxed) {
unsafe { (*pm).u_dval = x; } } else {
setfn_error(pm); }
}
pub fn ppf_unsetfn(pm: *mut crate::ported::zsh_h::param, explicit: i32) { if pm.is_null() { return; }
let pm_level = unsafe { (*pm).level };
if crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) <= pm_level { unsafe { (*pm).u_dval = 0.0; } }
if explicit != 0 { unsafe { (*pm).node.flags |= crate::ported::zsh_h::PM_DECLARED as i32; }
} else {
if let Ok(mut p) = PRIVATE_PARAMS.lock() {
unsafe { p.remove(&(*pm).node.nam); }
}
}
}
pub fn ppa_getfn(pm: *mut crate::ported::zsh_h::param) -> Vec<String> { if pm.is_null() { return Vec::new(); }
let pm_level = unsafe { (*pm).level };
if crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) >= pm_level { unsafe { (*pm).u_arr.clone().unwrap_or_default() } } else {
Vec::new() }
}
pub fn ppa_setfn(pm: *mut crate::ported::zsh_h::param, x: Vec<String>) { if pm.is_null() { return; }
let pm_level = unsafe { (*pm).level };
if crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) == pm_level
|| crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) > private_wraplevel.load(std::sync::atomic::Ordering::Relaxed) {
unsafe { (*pm).u_arr = Some(x); } } else {
setfn_error(pm); }
}
pub fn ppa_unsetfn(pm: *mut crate::ported::zsh_h::param, explicit: i32) { if pm.is_null() { return; }
let pm_level = unsafe { (*pm).level };
if crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) <= pm_level { unsafe { (*pm).u_arr = None; } }
if explicit != 0 { unsafe { (*pm).node.flags |= crate::ported::zsh_h::PM_DECLARED as i32; }
} else {
if let Ok(mut p) = PRIVATE_PARAMS.lock() {
unsafe { p.remove(&(*pm).node.nam); }
}
}
}
pub fn pph_getfn(pm: *mut crate::ported::zsh_h::param) -> Option<()> { if pm.is_null() { return None; }
let pm_level = unsafe { (*pm).level };
if crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) >= pm_level { unsafe { (*pm).u_hash.as_ref().map(|_| ()) } } else {
None }
}
pub fn pph_setfn(pm: *mut crate::ported::zsh_h::param, x: Option<crate::ported::zsh_h::HashTable>) { if pm.is_null() { return; }
let pm_level = unsafe { (*pm).level };
if crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) == pm_level
|| crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) > private_wraplevel.load(std::sync::atomic::Ordering::Relaxed) {
unsafe { (*pm).u_hash = x; } } else {
setfn_error(pm); }
}
pub fn pph_unsetfn(pm: *mut crate::ported::zsh_h::param, explicit: i32) { if pm.is_null() { return; }
let pm_level = unsafe { (*pm).level };
if crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed) <= pm_level { unsafe { (*pm).u_hash = None; } }
if explicit != 0 { unsafe { (*pm).node.flags |= crate::ported::zsh_h::PM_DECLARED as i32; }
} else {
if let Ok(mut p) = PRIVATE_PARAMS.lock() {
unsafe { p.remove(&(*pm).node.nam); }
}
}
}
pub fn bin_private(nam: &str, args: &[String], ops: &mut crate::ported::zsh_h::options, func: i32,
assigns: &mut Vec<(String, String)>) -> i32 {
let mut from_typeset: i32 = 1; let ofake = FAKELEVEL.load(Ordering::Relaxed); let hasargs = !assigns.is_empty(); MAKEPRIVATE_ERROR.store(0, Ordering::Relaxed);
if !OPT_ISSET(ops, b'P') { FAKELEVEL.store(0, Ordering::Relaxed); from_typeset = crate::ported::builtin::bin_typeset(nam, args, ops, func); FAKELEVEL.store(ofake, Ordering::Relaxed); return from_typeset; }
if OPT_ISSET(ops, b'T') { crate::ported::utils::zwarn("bad option: -T"); return 1; }
let locallevel = crate::ported::builtin::LOCALLEVEL.load(Ordering::Relaxed);
if locallevel == 0 { let warn = crate::ported::zsh_h::isset(crate::ported::options::optlookup("warncreateglobal"));
if warn { zwarnnam(nam, "invalid local scope, using globals"); }
return crate::ported::builtin::bin_typeset("private", args, ops, func); }
if !(OPT_ISSET(ops, b'm') || OPT_ISSET(ops, b'+')) { ops.ind[b'g' as usize] = 2; }
if OPT_ISSET(ops, b'p') || OPT_ISSET(ops, b'm') || (!hasargs && OPT_ISSET(ops, b'+'))
{
return crate::ported::builtin::bin_typeset("private", args, ops, func); }
crate::ported::mem::queue_signals(); FAKELEVEL.store(locallevel, Ordering::Relaxed); let mut paramscope_buf = crate::ported::params::newparamtable(17, "private_scope")
.unwrap_or_else(|| Box::new(crate::ported::zsh_h::hashtable {
hsize: 0, ct: 0, nodes: Vec::new(), tmpdata: 0,
hash: None, emptytable: None, filltable: None, cmpnodes: None,
addnode: None, getnode: None, getnode2: None, removenode: None,
disablenode: None, enablenode: None, freenode: None,
printnode: None, scantab: None,
}));
crate::ported::params::startparamscope(&mut paramscope_buf); from_typeset = crate::ported::builtin::bin_typeset("private", args, ops, func); crate::ported::params::endparamscope(); FAKELEVEL.store(ofake, Ordering::Relaxed); crate::ported::mem::unqueue_signals();
let mpe = MAKEPRIVATE_ERROR.load(Ordering::Relaxed);
mpe | from_typeset }
pub const PM_WAS_UNSET: u32 = crate::ported::zsh_h::PM_NORESTORE; pub const PM_WAS_RONLY: u32 = crate::ported::zsh_h::PM_RESTRICTED;
pub fn getprivatenode(pm: *mut crate::ported::zsh_h::param) -> *mut crate::ported::zsh_h::param
{
let mut cur = pm;
if cur.is_null() { return cur; }
let pm_flags = unsafe { (*cur).node.flags };
if (pm_flags & crate::ported::zsh_h::PM_AUTOLOAD as i32) != 0 {
}
while !cur.is_null() {
let cur_level = unsafe { (*cur).level };
let fakelvl = FAKELEVEL.load(std::sync::atomic::Ordering::Relaxed);
let local = crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed);
let pwl = private_wraplevel.load(std::sync::atomic::Ordering::Relaxed);
if !(fakelvl == 0 && local > cur_level && is_private(cur) != 0) { break; }
if cur_level == pwl + 1 { break; } cur = unsafe {
(*cur).old.as_mut().map(|b| &mut **b as *mut _).unwrap_or(std::ptr::null_mut())
};
}
if !cur.is_null() {
let f = unsafe { (*cur).node.flags };
if (f & crate::ported::zsh_h::PM_NAMEREF as i32) != 0 {
}
}
cur }
pub fn getprivatenode2(pm: *mut crate::ported::zsh_h::param) -> *mut crate::ported::zsh_h::param
{
let mut cur = pm;
while !cur.is_null() {
let cur_level = unsafe { (*cur).level };
let fakelvl = FAKELEVEL.load(std::sync::atomic::Ordering::Relaxed);
let local = crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed);
if !(fakelvl == 0 && local > cur_level && is_private(cur) != 0) { break; }
cur = unsafe {
(*cur).old.as_mut().map(|b| &mut **b as *mut _).unwrap_or(std::ptr::null_mut())
};
}
cur }
pub fn scopeprivate(hn: *mut crate::ported::zsh_h::param, onoff: i32) { if hn.is_null() { return; }
let pm_level = unsafe { (*hn).level };
let local = crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed);
if pm_level != local { return; } if is_private(hn) == 0 { return; } unsafe {
let f = (*hn).node.flags;
if onoff == crate::ported::zsh_h::PM_UNSET as i32 { if (f & crate::ported::zsh_h::PM_UNSET as i32) != 0 {
(*hn).node.flags |= PM_WAS_UNSET as i32;
} else {
(*hn).node.flags |= crate::ported::zsh_h::PM_UNSET as i32;
}
if (f & crate::ported::zsh_h::PM_READONLY as i32) != 0 {
(*hn).node.flags |= PM_WAS_RONLY as i32;
} else {
(*hn).node.flags |= crate::ported::zsh_h::PM_READONLY as i32;
}
} else { if (f & PM_WAS_UNSET as i32) != 0 {
(*hn).node.flags |= crate::ported::zsh_h::PM_UNSET as i32;
} else {
(*hn).node.flags &= !(crate::ported::zsh_h::PM_UNSET as i32);
}
if (f & PM_WAS_RONLY as i32) != 0 {
(*hn).node.flags |= crate::ported::zsh_h::PM_READONLY as i32;
} else {
(*hn).node.flags &= !(crate::ported::zsh_h::PM_READONLY as i32);
}
(*hn).node.flags &= !((PM_WAS_UNSET | PM_WAS_RONLY) as i32);
}
}
}
pub fn wrap_private(_prog: *const crate::ported::zsh_h::eprog, _w: *const crate::ported::zsh_h::funcwrap,
_name: *mut libc::c_char) -> i32 { let local = crate::ported::params::locallevel.load(std::sync::atomic::Ordering::Relaxed);
let pwl = private_wraplevel.load(std::sync::atomic::Ordering::Relaxed);
if pwl < local { let owl = pwl; private_wraplevel.store(local, std::sync::atomic::Ordering::Relaxed); private_wraplevel.store(owl, std::sync::atomic::Ordering::Relaxed); return 0; }
1 }
use crate::ported::zsh_h::module;
#[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)
}
#[allow(non_upper_case_globals)]
pub static emptytable: std::sync::Mutex<Option<crate::ported::zsh_h::HashTable>> =
std::sync::Mutex::new(None);
#[allow(unused_variables)]
pub fn boot_(m: *const module) -> i32 { if let Some(t) = crate::ported::params::newparamtable(1, "private") { if let Ok(mut e) = emptytable.lock() {
*e = Some(t);
}
}
0 }
pub fn cleanup_(m: *const module) -> i32 {
setfeatureenables(m, module_features(), None)
}
#[allow(unused_variables)]
pub fn finish_(m: *const module) -> i32 { if let Ok(mut e) = emptytable.lock() {
if let Some(t) = e.take() { crate::ported::params::deleteparamtable(Some(t));
}
}
0 }
#[cfg(test)]
mod tests {
use super::*;
fn empty_ops_pp() -> crate::ported::zsh_h::options {
use crate::ported::zsh_h::{options, MAX_OPS};
options { ind: [0u8; MAX_OPS], args: Vec::new(),
argscount: 0, argsalloc: 0 }
}
#[test]
fn bin_private_no_args_returns_zero() {
let mut ops = empty_ops_pp();
let mut assigns: Vec<(String, String)> = Vec::new();
assert_eq!(bin_private("private", &[], &mut ops, 0, &mut assigns), 0);
}
#[test]
fn bin_private_scalar_assign() {
let mut ops = empty_ops_pp();
ops.ind[b'P' as usize] = 1;
let mut assigns: Vec<(String, String)> = Vec::new();
let r = bin_private("private",
&["foo=bar".to_string()], &mut ops, 0, &mut assigns);
assert_eq!(r, 0);
}
#[test]
fn bin_private_minus_p_minus_t_refused() {
let mut ops = empty_ops_pp();
ops.ind[b'P' as usize] = 1;
ops.ind[b'T' as usize] = 1;
let mut assigns: Vec<(String, String)> = Vec::new();
assert_eq!(bin_private("private", &[], &mut ops, 0, &mut assigns), 1);
}
#[test]
fn module_loaders_return_zero() {
let m: *const module = std::ptr::null();
let mut features: Vec<String> = Vec::new();
let mut enables: Option<Vec<i32>> = None;
assert_eq!(setup_(m), 0);
assert_eq!(features_(m, &mut features), 0);
assert_eq!(enables_(m, &mut enables), 0);
assert_eq!(boot_(m), 0);
assert_eq!(cleanup_(m), 0);
assert_eq!(finish_(m), 0);
}
}
use crate::ported::zsh_h::features as features_t;
use std::sync::{Mutex, OnceLock};
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: 0,
n_abstract: 0,
}))
}
fn featuresarray(_m: *const module, _f: &Mutex<features_t>) -> Vec<String> {
vec!["b:private".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; 1]);
}
0
}
fn setfeatureenables(
_m: *const module,
_f: &Mutex<features_t>,
_e: Option<&[i32]>,
) -> i32 {
0
}