luaur-cli-lib 0.1.0

Shared CLI helpers for the luaur tools.
Documentation
pub fn get_current_working_directory() -> Option<alloc::string::String> {
    const MAX_PATH_LENGTH: usize = 131072;
    const INITIAL_PATH_LENGTH: usize = 260;

    let mut buffer = alloc::vec![0u8; INITIAL_PATH_LENGTH];
    let mut current_len = INITIAL_PATH_LENGTH;

    loop {
        let result = unsafe {
            #[cfg(windows)]
            {
                use core::ffi::{c_char, c_int};
                extern "C" {
                    fn _getcwd(buffer: *mut c_char, maxlen: c_int) -> *mut c_char;
                }
                _getcwd(buffer.as_mut_ptr() as *mut c_char, buffer.len() as c_int)
            }
            #[cfg(not(windows))]
            {
                use core::ffi::{c_char, c_ulong};
                extern "C" {
                    fn getcwd(buffer: *mut c_char, size: usize) -> *mut c_char;
                }
                getcwd(buffer.as_mut_ptr() as *mut c_char, buffer.len())
            }
        };

        if !result.is_null() {
            let c_str = unsafe { core::ffi::CStr::from_ptr(result) };
            // The require resolver / VfsNavigator work in a forward-slash virtual
            // path space (they split and join on '/'). On Windows `_getcwd` returns
            // backslashes and a drive letter (e.g. `D:\a\luaur`), which the resolver
            // treated as one opaque component: the drive never componentized,
            // `absolute_path_prefix` kept backslashes while `get_module_path` stripped
            // the drive with forward slashes, and the two were concatenated into an
            // inconsistent cache key. That broke require cycle detection on Windows
            // (the same module got different keys), so a module that re-required
            // itself recursed forever -> stack overflow (0xC0000409) across the
            // require-by-string tests. Normalize to forward slashes here so Windows
            // drive-letter cwds flow through the resolver exactly like POSIX paths.
            // No-op on Unix (POSIX paths contain no backslashes).
            return Some(c_str.to_string_lossy().replace('\\', "/"));
        }

        let err = std::io::Error::last_os_error();
        if err.raw_os_error() != Some(34) || current_len * 2 > MAX_PATH_LENGTH {
            return None;
        }

        current_len *= 2;
        buffer.resize(current_len, 0);
    }
}