//
// Syd: rock-solid application kernel
// src/utils/syd-rnd.rs: print AT_RANDOM bytes in various formats
//
// Copyright (c) 2024, 2025, 2026 Ali Polatel <alip@chesswob.org>
//
// SPDX-License-Identifier: GPL-3.0

use std::{io::Write, process::ExitCode};

use nix::errno::Errno;
use syd::hash::{get_at_random, get_at_random_hex, get_at_random_name, get_at_random_u64};

// Set global allocator to GrapheneOS allocator.
#[cfg(all(
    not(coverage),
    not(feature = "prof"),
    not(target_os = "android"),
    not(target_arch = "riscv64"),
    target_page_size_4k,
    target_pointer_width = "64"
))]
#[global_allocator]
static GLOBAL: hardened_malloc::HardenedMalloc = hardened_malloc::HardenedMalloc;

// Set global allocator to tcmalloc if profiling is enabled.
#[cfg(feature = "prof")]
#[global_allocator]
static GLOBAL: tcmalloc::TCMalloc = tcmalloc::TCMalloc;

syd::main! {
    use lexopt::prelude::*;

    syd::set_sigpipe_dfl()?;

    // Parse CLI options.
    let mut opt_print_raw = false;
    let mut opt_print_int = false;
    let mut opt_print_nam = false;

    let mut parser = lexopt::Parser::from_env();
    while let Some(arg) = parser.next()? {
        match arg {
            Short('h') => {
                help();
                return Ok(ExitCode::SUCCESS);
            }
            Short('r') => opt_print_raw = true,
            Short('i') => opt_print_int = true,
            Short('n') => opt_print_nam = true,
            _ => return Err(arg.unexpected().into()),
        }
    }

    let flags = [opt_print_raw, opt_print_int, opt_print_nam];
    if flags.iter().filter(|&&flag| flag).count() > 1 {
        eprintln!("At most one of -i, -n, and -r must be given!");
        return Err(Errno::EINVAL.into());
    }

    if opt_print_raw {
        let stdout = std::io::stdout();
        let mut stdout = stdout.lock();
        stdout.write_all(get_at_random())?;
    } else if opt_print_int {
        let (i, _) = get_at_random_u64();
        println!("{i}");
    } else if opt_print_nam {
        println!("{}", get_at_random_name(0));
    } else {
        print!("{}", get_at_random_hex(false));
    }

    Ok(ExitCode::SUCCESS)
}

fn help() {
    println!("Usage: syd-rnd [-hinr]");
    println!("Print AT_RANDOM bytes in various formats");
    println!("Given no arguments, print AT_RANDOM bytes in lower hexadecimal format.");
    println!("Given *-r*, print raw bytes.");
    println!("Given *-i*, print an unsigned 64-bit integer.");
    println!("Given *-n*, print a human-readable name.")
}
