use std::sync::atomic::{AtomicI32, AtomicUsize, Ordering};
use std::sync::Mutex;
pub static noexitct: AtomicI32 = AtomicI32::new(0);
pub static zunderscore: Mutex<String> = Mutex::new(String::new());
pub static underscorelen: AtomicUsize = AtomicUsize::new(0);
pub static underscoreused: AtomicI32 = AtomicI32::new(0);
pub static sourcelevel: AtomicI32 = AtomicI32::new(0);
pub static SHTTY: AtomicI32 = AtomicI32::new(-1);
pub static shout: Mutex<usize> = Mutex::new(0);
pub static tcstr: Mutex<[String; 39]> = Mutex::new([ String::new(), String::new(), String::new(), String::new(), String::new(),
String::new(), String::new(), String::new(), String::new(), String::new(),
String::new(), String::new(), String::new(), String::new(), String::new(),
String::new(), String::new(), String::new(), String::new(), String::new(),
String::new(), String::new(), String::new(), String::new(), String::new(),
String::new(), String::new(), String::new(), String::new(), String::new(),
String::new(), String::new(), String::new(), String::new(), String::new(),
String::new(), String::new(), String::new(), String::new(),
]);
pub static tclen: Mutex<[i32; 39]> = Mutex::new([0; 39]);
pub static tclines: AtomicI32 = AtomicI32::new(0);
pub static tccolumns: AtomicI32 = AtomicI32::new(0);
pub static hasam: AtomicI32 = AtomicI32::new(0);
pub static hasxn: AtomicI32 = AtomicI32::new(0);
pub static tccolours: AtomicI32 = AtomicI32::new(0);
pub static zshhooks: Mutex<[crate::ported::zsh_h::hookdef; 4]> = Mutex::new([ crate::ported::zsh_h::hookdef { next: None, name: String::new(), def: None, flags: 1, funcs: None,
},
crate::ported::zsh_h::hookdef { next: None, name: String::new(), def: None, flags: 1, funcs: None,
},
crate::ported::zsh_h::hookdef { next: None, name: String::new(), def: None, flags: 1, funcs: None,
},
crate::ported::zsh_h::hookdef { next: None, name: String::new(), def: None, flags: 1, funcs: None,
},
]);
static argv0: Mutex<String> = Mutex::new(String::new());
pub static zle_entry_ptr: AtomicUsize = AtomicUsize::new(0);
pub static zle_load_state: AtomicI32 = AtomicI32::new(0);
pub static compctlreadptr: AtomicUsize = AtomicUsize::new(0);
pub static use_exit_printed: AtomicI32 = AtomicI32::new(0);
const tccapnams: [&str; 39] = [ "cl", "le", "LE", "nd", "RI", "up", "UP", "do",
"DO", "dc", "DC", "ic", "IC", "cd", "ce", "al", "dl", "ta",
"md", "mh", "so", "us", "ZH", "me", "se", "ue", "ZR", "ch",
"ku", "kd", "kl", "kr", "sc", "rc", "bc", "AF", "AB", "vi", "ve",
];
pub fn r#loop(toplevel: i32, justonce: i32) -> i32 { let mut err: i32; let mut non_empty: i32 = 0;
crate::ported::signals::queue_signals(); crate::ported::mem::pushheap(); if toplevel == 0 { }
loop { crate::ported::mem::freeheap(); use_exit_printed.store(0, Ordering::SeqCst); crate::ported::signals::intr(); if justonce != 0 { break; } break;
}
err = 0; if toplevel == 0 { }
crate::ported::mem::popheap(); crate::ported::signals::unqueue_signals();
if err != 0 { return 2; } if non_empty == 0 { return 1; } 0 }
fn parseargs(zsh_name: &str, argv: &mut Vec<String>, runscript: &mut Option<String>, cmdptr: &mut Option<String>) {
let mut idx: usize = 0; let flags: i32 = 1; let flags = if argv.first().map(|s| s.starts_with('-')).unwrap_or(false) { flags | 2 } else { flags };
*argv0.lock().unwrap() = argv[idx].clone(); idx += 1;
let _ = parseopts(zsh_name, argv, &mut idx, cmdptr, flags);
let mut paramlist: Vec<String> = Vec::new();
if idx < argv.len() { if cmdptr.is_none() { *runscript = Some(argv[idx].clone());
}
idx += 1;
while idx < argv.len() { paramlist.push(argv[idx].clone());
idx += 1;
}
} else if cmdptr.is_none() { }
let _ = paramlist;
}
fn parseopts_insert(optlist: &mut Vec<usize>, base: usize, optno: i32) { let ptr = base + (if optno < 0 { -optno } else { optno }) as usize; for (i, &node) in optlist.iter().enumerate() { if ptr < node { optlist.insert(i, ptr); return; }
}
optlist.push(ptr); }
fn parseopts_setemulate(_nam: &str, _flags: i32) { }
pub fn parseopts(_nam: &str, argv: &mut Vec<String>, idx: &mut usize, cmdp: &mut Option<String>, flags: i32) -> i32 {
let toplevel = (flags & 1) != 0; let mut emulate_required = toplevel; *cmdp = None;
while *idx < argv.len() { let arg = argv[*idx].clone();
if !(arg.starts_with('-') || arg.starts_with('+')) { break; }
if arg == "--version" { println!("zshrs (C-port)"); if toplevel { std::process::exit(0); } }
if arg == "--help" { printhelp(); if toplevel { std::process::exit(0); } }
if arg == "-c" { if emulate_required { parseopts_setemulate(_nam, flags); emulate_required = false; }
*idx += 1;
*cmdp = argv.get(*idx).cloned(); *idx += 1;
continue;
}
*idx += 1;
}
if emulate_required { parseopts_setemulate(_nam, flags); }
0 }
fn printhelp() { let argz = argv0.lock().unwrap().clone(); println!("Usage: {} [<options>] [<argument> ...]", argz); println!(); println!("Special options:"); println!(" --help show this message, then exit"); println!(" --version show zsh version number, then exit"); println!(" -b end option processing, like --"); println!(" -c take first argument as a command to execute"); println!(" -o OPTION set an option by name (see below)"); println!(); println!("Normal options are named. An option may be turned on by"); println!("`-o OPTION', `--OPTION', `+o no_OPTION' or `+-no-OPTION'. An"); println!("option may be turned off by `-o no_OPTION', `--no-OPTION',"); println!("`+o OPTION' or `+-OPTION'. Options are listed below only in"); println!("`--OPTION' or `--no-OPTION' form."); }
pub fn init_io(_cmd: Option<&str>) {
*shout.lock().unwrap() = 0;
if SHTTY.load(Ordering::SeqCst) != -1 { unsafe { libc::close(SHTTY.load(Ordering::SeqCst)); } SHTTY.store(-1, Ordering::SeqCst); }
#[cfg(unix)]
unsafe {
if libc::isatty(0) == 1 { let name_ptr = libc::ttyname(0); if !name_ptr.is_null() {
let name = std::ffi::CStr::from_ptr(name_ptr);
let cstr = std::ffi::CString::new(name.to_bytes()).unwrap();
let fd = libc::open(cstr.as_ptr(), libc::O_RDWR | libc::O_NOCTTY);
SHTTY.store(crate::ported::utils::movefd(fd), Ordering::SeqCst);
}
if SHTTY.load(Ordering::SeqCst) == -1 { SHTTY.store(crate::ported::utils::movefd(libc::dup(0)),
Ordering::SeqCst); }
}
if SHTTY.load(Ordering::SeqCst) == -1 && libc::isatty(1) == 1 { SHTTY.store(crate::ported::utils::movefd(libc::dup(1)),
Ordering::SeqCst); }
if SHTTY.load(Ordering::SeqCst) == -1 { let dev_tty = std::ffi::CString::new("/dev/tty").unwrap();
let fd = libc::open(dev_tty.as_ptr(),
libc::O_RDWR | libc::O_NOCTTY); SHTTY.store(crate::ported::utils::movefd(fd), Ordering::SeqCst);
}
if SHTTY.load(Ordering::SeqCst) != -1 { let fdflags = libc::fcntl(SHTTY.load(Ordering::SeqCst),
libc::F_GETFD, 0); if fdflags != -1 { libc::fcntl(SHTTY.load(Ordering::SeqCst), libc::F_SETFD, fdflags | libc::FD_CLOEXEC);
}
}
}
init_shout();
let _ = crate::ported::jobs::acquire_pgrp();
}
pub fn init_shout() { if SHTTY.load(Ordering::SeqCst) == -1 { return;
}
let _ = crate::ported::utils::gettyinfo(); }
pub fn tccap_get_name(cap: usize) -> &'static str { if cap >= 39 { return ""; }
tccapnams[cap] }
pub fn init_term() -> i32 { let term = std::env::var("TERM").unwrap_or_default();
if term.is_empty() {
crate::ported::params::TERMFLAGS.fetch_or(1, Ordering::SeqCst);
return 0;
}
if term == "emacs" { }
1 }
fn getmypath(name: Option<&str>, cwd: Option<&str>) -> Option<String> { #[cfg(target_os = "macos")]
unsafe { let mut buf = vec![0u8; libc::PATH_MAX as usize]; let mut n: u32 = libc::PATH_MAX as u32; let ret = libc::_NSGetExecutablePath(buf.as_mut_ptr() as *mut i8, &mut n);
if ret < 0 { buf.resize(n as usize, 0); let ret2 = libc::_NSGetExecutablePath(
buf.as_mut_ptr() as *mut i8, &mut n); if ret2 == 0 {
let s = std::ffi::CStr::from_ptr(buf.as_ptr() as *const i8);
let lossy = s.to_string_lossy().into_owned();
if !lossy.is_empty() { return Some(lossy); }
}
} else if ret == 0 { let s = std::ffi::CStr::from_ptr(buf.as_ptr() as *const i8);
let lossy = s.to_string_lossy().into_owned();
if !lossy.is_empty() { return Some(lossy); } }
}
#[cfg(target_os = "linux")]
{
if let Ok(p) = std::fs::read_link("/proc/self/exe") { return Some(p.to_string_lossy().into_owned()); }
}
let name = name?; let name = if name.starts_with('-') { &name[1..] } else { name }; let namelen = name.len(); if namelen == 0 { return None; } if name.ends_with('/') { return None; } if name.starts_with('/') { return Some(name.to_string()); }
if name.contains('/') { let cwd = cwd?; return Some(format!("{}/{}", cwd, name)); }
let path = std::env::var("PATH").ok()?; if path.is_empty() { return None; } for dir in path.split(':') { let candidate = if dir.is_empty() {
std::path::PathBuf::from(name)
} else {
std::path::PathBuf::from(format!("{}/{}", dir, name))
};
if let Ok(real) = std::fs::canonicalize(&candidate) { if real.is_file() {
return Some(real.to_string_lossy().into_owned());
}
}
}
None }
pub fn setupvals(cmd: Option<&str>, runscript: Option<&str>, zsh_name: &str) { let mut close_fds = [0i32; 10]; let mut tmppipe = [-1i32; 2];
#[cfg(unix)]
unsafe {
if libc::pipe(tmppipe.as_mut_ptr()) == 0 { let mut i: i32 = -1; while i < 9 { let j: i32;
if i < tmppipe[0] { j = tmppipe[0]; } else if i < tmppipe[1] { j = tmppipe[1]; } else {
j = libc::dup(0); if j == -1 { break; } }
if j < 10 { close_fds[j as usize] = 1; } else {
libc::close(j); }
if i < j { i = j; } }
if i < tmppipe[0] { libc::close(tmppipe[0]); } if i < tmppipe[1] { libc::close(tmppipe[1]); } }
}
let _ = crate::ported::hist::inithist();
crate::ported::params::TERMFLAGS.store(1, Ordering::SeqCst);
#[cfg(unix)]
unsafe {
let mut ts: libc::timespec = std::mem::zeroed();
libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut ts);
libc::srand((ts.tv_sec as u32).wrapping_add(ts.tv_nsec as u32));
}
std::env::set_var("PATH", std::env::var("PATH").unwrap_or_else(|_|
"/bin:/usr/bin:/usr/ucb:/usr/local/bin".to_string()));
let underscore_val = std::env::var("_").unwrap_or_default(); let metafied = crate::ported::utils::metafy(&underscore_val); *zunderscore.lock().unwrap() = metafied.clone(); underscoreused.store((metafied.len() + 1) as i32, Ordering::SeqCst); let ulen = (metafied.len() + 1 + 31) & !31; underscorelen.store(ulen, Ordering::SeqCst);
if let Ok(home) = std::env::var("HOME") { let _ = home;
}
if let Some(cwd) = crate::ported::utils::zgetcwd() { std::env::set_var("PWD", &cwd);
if std::env::var("OLDPWD").is_err() { std::env::set_var("OLDPWD", &cwd);
}
}
crate::ported::utils::inittyptab();
crate::ported::hashtable::createreswdtable(); crate::ported::hashtable::createaliastables(); crate::ported::hashtable::createcmdnamtable(); crate::ported::hashtable::createshfunctable(); let _ = crate::ported::builtin::createbuiltintable(); crate::ported::params::createparamtable();
let (_cols, _lines) = crate::ported::utils::adjustwinsize();
sourcelevel.store(0, Ordering::SeqCst);
#[cfg(unix)]
for i in 0..10 { if close_fds[i] != 0 { unsafe { libc::close(i as i32); } }
}
let _ = crate::ported::prompt::set_default_colour_sequences();
{
let exename = argv0.lock().unwrap().clone(); let exename = crate::ported::utils::unmeta(&exename); let cwd = crate::ported::params::getsparam("PWD").map(|s|
crate::ported::utils::unmeta(&s));
let mypath = getmypath(Some(&exename), cwd.as_deref());
if let Some(mp) = mypath { std::env::set_var("ZSH_EXEPATH", &mp); }
}
if let Some(cmd) = cmd { std::env::set_var("ZSH_EXECUTION_STRING", cmd); }
if let Some(rs) = runscript { std::env::set_var("ZSH_SCRIPT", rs); }
std::env::set_var("ZSH_NAME", zsh_name); }
fn setupshin(runscript: Option<&str>) { if let Some(script) = runscript { let funmeta = crate::ported::utils::unmeta(script); let mut sfname: Option<String> = None; if std::path::Path::new(&funmeta).is_file() { sfname = Some(script.to_string()); }
if sfname.is_none() { crate::ported::utils::zerr(&format!( "can't open input file: {}", script));
std::process::exit(127); }
}
}
pub fn init_signals() {
crate::ported::signals::intr();
#[cfg(unix)]
unsafe {
let mut act: libc::sigaction = std::mem::zeroed(); if libc::sigaction(libc::SIGQUIT, std::ptr::null(), &mut act) == 0 && act.sa_sigaction == libc::SIG_IGN
{
}
let mut ign: libc::sigaction = std::mem::zeroed(); ign.sa_sigaction = libc::SIG_IGN;
libc::sigaction(libc::SIGQUIT, &ign, std::ptr::null_mut());
crate::ported::signals::install_handler(libc::SIGHUP); crate::ported::signals::install_handler(libc::SIGCHLD); #[cfg(not(target_os = "haiku"))]
crate::ported::signals::install_handler(libc::SIGWINCH);
crate::ported::signals::install_handler(libc::SIGPIPE); crate::ported::signals::install_handler(libc::SIGALRM); libc::sigaction(libc::SIGTERM, &ign, std::ptr::null_mut());
libc::sigaction(libc::SIGTTOU, &ign, std::ptr::null_mut()); libc::sigaction(libc::SIGTSTP, &ign, std::ptr::null_mut()); libc::sigaction(libc::SIGTTIN, &ign, std::ptr::null_mut()); }
}
pub fn run_init_scripts() {
let emul = crate::ported::options::emulation.load(Ordering::SeqCst);
let is_posix = (emul & 6) != 0;
if is_posix {
} else {
let _ = source(crate::ported::config_h::GLOBAL_ZSHENV);
sourcehome(".zshenv");
sourcehome(".zshrc");
}
}
pub fn init_misc(cmd: Option<&str>, zsh_name: &str) { if zsh_name.starts_with('r') { crate::ported::utils::zerrnam(zsh_name, "no support for restricted mode");
std::process::exit(1); }
if let Some(cmdstr) = cmd { let _ = cmdstr;
std::process::exit(0);
}
}
pub fn source(s: &str) -> i32 { let _us = crate::ported::utils::unmeta(s); let path = std::path::Path::new(&_us);
if !path.exists() { return 1;
}
let oldlineno = 0i64; let _ = oldlineno;
sourcelevel.fetch_add(1, Ordering::SeqCst);
let _ = std::fs::read_to_string(path);
sourcelevel.fetch_sub(1, Ordering::SeqCst);
0 }
pub fn sourcehome(s: &str) { crate::ported::signals::queue_signals(); let emul = crate::ported::options::emulation.load(Ordering::SeqCst);
let is_posix = (emul & 6) != 0;
let h = if is_posix {
crate::ported::params::getsparam("HOME")
} else {
crate::ported::params::getsparam("ZDOTDIR")
.or_else(|| crate::ported::params::getsparam("HOME"))
};
let h = match h { Some(h) => h,
None => {
crate::ported::signals::unqueue_signals();
return;
}
};
let buf = format!("{}/{}", h, s); crate::ported::signals::unqueue_signals(); source(&buf); }
pub fn init_bltinmods() { }
pub fn noop_function() { }
pub fn noop_function_int(_nothing: i32) { }
pub fn zleentry(cmd: i32) -> Option<String> { let mut cmd = cmd;
match zle_load_state.load(Ordering::SeqCst) { 0 => { if cmd != 1 && cmd != 2 && cmd != 3 { zle_load_state.store(2, Ordering::SeqCst); }
}
1 => { cmd = -1; }
2 => { } _ => {}
}
match cmd { 4 => { let _line = String::new(); return Some(String::new());
}
5 => { return Some(String::new()); }
_ => {}
}
None }
pub fn fallback_compctlread(name: &str) -> i32 { crate::ported::utils::zwarnnam(name, "no loaded module provides read for completion context");
1 }
pub fn zsh_main(_argc: i32, argv: &[String]) -> i32 { #[cfg(unix)]
unsafe {
let empty = std::ffi::CString::new("").unwrap();
libc::setlocale(libc::LC_ALL, empty.as_ptr()); }
let env: Vec<String> = std::env::vars()
.map(|(k, v)| format!("{}={}", k, v))
.collect();
let _ = crate::ported::jobs::init_jobs(argv, &env);
let mut zsh_name = argv.first().cloned().unwrap_or_default(); loop { let arg0 = zsh_name.clone(); zsh_name = match arg0.rfind('/') { None => arg0.clone(), Some(i) => arg0[i+1..].to_string(), };
if zsh_name.starts_with('-') { zsh_name = zsh_name[1..].to_string(); }
if zsh_name == "su" { if let Ok(sh) = std::env::var("SHELL") { if !sh.is_empty() && arg0 != sh { zsh_name = sh; continue; }
}
break; }
break; }
let _ = crate::ported::compat::zopenmax();
crate::ported::options::createoptiontable();
let mut argv_v = argv.to_vec();
let mut runscript: Option<String> = None; let mut cmd: Option<String> = None; parseargs(&zsh_name, &mut argv_v, &mut runscript, &mut cmd);
SHTTY.store(-1, Ordering::SeqCst); init_io(cmd.as_deref()); setupvals(cmd.as_deref(), runscript.as_deref(), &zsh_name);
init_signals(); init_bltinmods(); crate::ported::builtin::init_builtins(); run_init_scripts(); setupshin(runscript.as_deref()); init_misc(cmd.as_deref(), &zsh_name);
loop { let mut errexit = 0; loop { let _ = r#loop(1, 0); errexit = 1;
break;
}
if errexit != 0 { std::process::exit(0);
}
std::process::exit(0);
}
}