#![feature(
    try_trait_v2,
    decl_macro,
    maybe_uninit_array_assume_init,
    c_variadic,
    arbitrary_self_types_pointers,
    maybe_uninit_slice,
    slice_internals,
    linkage,
    rustc_private,
    thread_local,
    let_chains,
    int_roundings,
    link_llvm_intrinsics
)]
#![allow(
    internal_features,
    clippy::unnecessary_fallible_conversions,
    clippy::useless_conversion,
    clippy::identity_op,
    clippy::missing_safety_doc,
    clippy::missing_transmute_annotations,
    clippy::upper_case_acronyms
)]
#![cfg_attr(not(test), no_std)]

use core::{
    ffi::{c_char, c_int},
    ptr::null,
};

use alloc::vec::Vec;
use env::environ;
use thread::Thread;

extern crate alloc;

extern crate compiler_builtins;

#[cfg(test)]
extern crate std;

mod allocator;
mod cxxabi;
mod debug;
mod env;
mod error;
mod init;
mod io;
mod panic;
mod process;
mod random;
mod signal;
mod ssp;
mod thread;
mod types;
mod util;

pub mod headers;

#[no_mangle]
unsafe extern "C" fn __ygglibc_entry(
    main: extern "C" fn(c_int, *const *const c_char, *const *const c_char) -> c_int,
    arg: usize,
) {
    // Setup a logging sink
    debug::init_log_sink();
    init::call_constructors();
    signal::init(true);
    init::init();

    // Setup args
    let args = env::handle_kernel_argument(arg);
    let mut c_args = Vec::new();

    for arg in args.iter() {
        c_args.push(arg.as_ptr());
    }
    c_args.push(null());

    let status = main(
        args.len().try_into().unwrap(),
        c_args.as_ptr(),
        environ.cast(),
    );

    // Call main thread dtors
    Thread::call_thread_dtors();

    process::c_exit(status)
}
